this is probably a more general programming question and something that has been on my mind.
I only have 1 year of experience, and recently started reading the book "Clean Code" and stumbling upon The Big 0 Notation.
These two things basically say that you should never loop through something twice (Loop inside of loop), because the performance is terrible (O(2n) if i remember correctly).
My question is this:
If i have this structure which is an array of all of the orders on my app, and inside of this array, there is an object, this object contains another array, which is the individual product that was in that order.
[
orderOne: {
products: [
{name: "Life advice", price: 399},
{name: "Test", price: 429},
],
userInformation: {
name: "John",
age: 21
}
}
]
Now in order to display all of the orders in my view, I would need to first loop through the total orders, and then inside of that loop, I loop through the products array inside, which creates this double loop.
How would this be avoided? It feels inevitable that there is going to be an array inside of an array for data storing, which would always then mean a double loop.
I am trying to get better at understanding ways of structuring things instead of going head first and just writing double loops everywere.
Thank you so much for your time!
Stay safe!
It really depends on what you're trying to achieve...
If you're just displaying the orders then does each order need to display each item all at the same time?
Would it not be more logical to display the items of an order once it is selected?
It's best to consider the scope of your data when thinking about how to manipulate it. This way, you're only handling data upon the user needing to access it, which should reduce loading/refresh times.
There will be times when nested loops are required, but many cases where it seems like it's required you can actually defer the consumption of the data until a later date when it becomes more relevant.
You could also have a separate array of products, each with an ID and then the order object just has a dictionary of product IDs and quantities. This can then be resolved into a full list for displaying fairly quickly.
Related
My app has geofencing functionality. In the UI there is a table which lets the user add a country to either the "blocked" or the "allowed" list. The overwhelming majority of objects in the collection do not need geofencing and thus by default all countries should be in the allowed list for a new object.
How do I represent the 3 possible states (all, some, none) in Mongo? The last two are obvious - an array containing either some 2 letter country codes, or none. But what about the first case? I feel like it would be a massive waste of bytes to store however many (200+) country codes for each object.
The two alternatives I can come up with are:
Using a value of object.allowed_countries = [ 1 ] which also doesn't scream right to me.
Or storing an additional property to represent the global "all".
object: {
geofencing: {
enabled: true | false,
blocked_countries: [ ]
}
}
Is there anything smarter I'm not thinking of?
Thank you in advance!
Possibly very stupid question I cannot seem to find an answer for (I am beginning with code)
I want to create a simple loop which appends myArray with three objects, which are members of a custom class MyClass. The objects have the following names: "object1", "object2", "object3".
When I write the following code, there is no issue:
myArray.append(object1)
But I want to write a loop to add all three. Again, very dumb, but I can't figure out how to insert the number in the name of the object as a variable. E.g., here was something I tried
let x = 3
for i in 1...x {
myArray.append(object[i])
}
This gives an error. The reason I want to do it using a loop, and not simply write in the three objects manually, is that I won't always loop three times. Sometimes I'll just want the first two objects, sometimes just the first.
I assume there's some easy way to do this, but when I search it tends to turn up more complex questions
I have a simple Person class in Swift that looks about like this:
class Person {
var name = "John Doe"
var age = 18
var children = [Person]?
\\ init function goes here, but does not initialize children array
}
Instead of declaring children to be an optional array, I could simply declare it and initialize it as an empty array like this:
var children = [Person]()
I am trying to decide which approach is better. Declaring the array as an optional array means that it will not take up any memory at all, whereas an empty array has at least some memory allocated for it, correct? So using the optional array means that there will be at least some memory saving. I guess my first question is: Is there really any actual memory saving involved here, or are my assumptions about this incorrect?
On the other hand, if it is optional then each time I try to use it I will have to check to see if it is nil or not before adding or removing objects from it. So there will be be some loss of efficiency there (but not much, I imagine).
I kind of like the optional approach. Not every Person will have children, so why not let children be nil until the Person decides to settle down and raise a family?
At any rate, I would like to know if there are any other specific advantages or disadvantages to one approach or the other. It is a design question that will come up over and over again.
I'm going to make the opposite case from Yordi - an empty array just as clearly says "this Person has no children", and will save you a ton of hassle. children.isEmpty is an easy check for the existence of kids, and you won't ever have to unwrap or worry about an unexpected nil.
Also, as a note, declaring something as optional doesn't mean it takes zero space - it's the .None case of an Optional<Array<Person>>.
The ability to choose between an empty array or an optional gives us the ability to apply the one that better describe the data from a semantic point of view.
I would choose:
An empty array if the list can be empty, but it's a transient status and in the end it should have at least one element. Being non optional makes clear that the array should not be empty
An optional if it's possible for the list to be empty for the entire life cycle of the container entity. Being an optional makes clear that the array can be empty
Let me make some examples:
Purchase order with master and details (one detail per product): a purchase order can have 0 details, but that's a transient status, because it wouldn't make sense having a purchase order with 0 products
Person with children: a person can have no children for his entire life. It is not a transient status (although not permanent as well), but using an optional it's clear that it's legit for a person to have no children.
Note that my opinion is only about making the code more clear and self-explainatory - I don't think there is any significant difference in terms of performance, memory usage, etc. for choosing one option or the other.
Interestingly enough, we have recently had few discussions regarding this very same question at work.
Some suggest that there are subtle semantic differences. E.g. nil means a person has no children whatsoever, but then what does 0 mean? Does it mean "has children, the whole 0 of them"? Like I said, pure semantics "has 0 children" and "has no children" makes no difference when working with this model in code. In that case why not choosing more straightforwards and less guard-let-?-y approach?
Some suggest that keeping a nil there may be an indication that, for example, when fetching model from backend something went wrong and we got error instead of children. But I think model should not try to have this type of semantics and nil should not be used as indication of some error in the past.
I personally think that the model should be as dumb as possible and the dumbest option in this case is empty array.
Having an optional will make you drag that ? until the end of days and use guard let, if let or ?? over and over again.
You will have to have extra unwrapping logic for NSCoding implementation, you will have to do person.children?.count ?? 0 instead of straightforward person.children.count when you display that model in any view controller.
The final goal of all that manipulation is to display something on UI.
Would you really say
"This person has no children" and "This person has 0 children" for nil and empty array correspondingly? I hope you would not :)
Last Straw
Finally, and this is really the strongest argument I have
What is the type of subviews property of UIView: it's var subviews: [UIView] { get }
What is the type of children property of SKNode: it's var children: [SKNode] { get }
There's tons of examples like this in Cocoa framework: UIViewController::childViewControllers and more.
Even from pure Swift world: Dictionary::keys though this may be a bit far fetched.
Why is it OK for person to have nil children, but not for SKNode? For me the analogy is perfect. Hey, even the SKNode's method name is children :)
My view: there must be an obvious reason for keeping those arrays as optionals, like a really good one, otherwise empty array offers same semantics with less unwrapping.
The Last Last Straw
Finally, some references to very good articles, each of those
http://www.theswiftlearner.com/2015/05/08/empty-or-optional-arrays/
https://www.natashatherobot.com/ios-optional-vs-empty-data-source-swift/
In Natasha's post, you will find a link to NSHipster's blog post and in Swiftification paragraph you can read this:
For example, instead of marking NSArray return values as nullable, many APIs have been modified to return an empty array—semantically these have the same value (i.e., nothing), but a non-optional array is far simpler to work with
Sometimes there's a difference between something not existing and being empty.
Let's say we have an app where a user can modify a list of phone numbers and we save said modifications as modifiedPhoneNumberList. If no modification has ever occurred the array should be nil. If the user has modified the parsed numbers by deleting them all the array should be empty.
Empty means we're going to delete all the existing phone numbers, nil means we keep all the existing phone numbers. The difference matters here.
When we can't differentiate between a property being empty or not existing or it doesn't matter empty is the way to go. If a Person were to lose their only child we should simply have to remove that child and have an empty array rather than have to check if the count is 1 then set the entire array to nil.
I always use empty arrays.
In my humble opinion, the most important purpose of optionals in Swift is to safely wrap some value that may be nil. An array already act as this type of wrapper - you can ask the array if it has anything inside & access its value(s) safely with for loops, mapping, etc. Do we need to put a wrapper within a wrapper? I don't think so.
Swift is designed to take advantage of optional value's and optional unwrapping.
You could also declare the array as nil, as it will save you a very small (almost not noticable) amount of memory.
I would go with an optional array instead of an array that represents a nil value to keep Swift's Design Patterns happy :)
I also think
if let children = children {
}
looks nicer than :
if(children != nil){
}
I'm using Google Docs Spreadsheet API to keep track of a competition between some of my friends. I have some big ideas, but I'm stumped right now. I'm trying to create 20 different arrays inside of loops (see below) and then evaluate each one outside of the loop, and I really don't want to write 20 "if...then" statements.
NOTE: the following SUMMARY may or may not help you answer my question. You might want to skip down to the code, then read this if you need it :)
Summary of the program: Each player assigns point values in favor of one possible outcome of a set of binary-outcome events. As the events happen, players either gain the points assigned if their outcome occurs, or gain no points if the opposite outcome occurs. My goal is to 1) figure out exactly when a player is eliminated, and 2) highlight all remaining events that must be won for them to have a chance at tying for first.
Instead of trying to somehow evaluate all possibilities (5 players picking, 2^16 outcomes... I have zero computer science knowledge, but this seems like an incredibly huge task even for the modern computer) I've come up with an alternate idea. The script loops through each player, against each other opponent. It calculates the maximum number of points a player can score based on their value assignments and the already determined game. For one player and one opponent, it checks the best possible outcome by the player against that opponent, and if there is any opponent he cannot beat, even in the best case, then he is eliminated.
This part is easy-- after the loop runs inside the loop, I just adjust a global variable that I created earlier, and when the outer loop is done, just grab those variables and write them to the sheet.
Unfortunately, this misses the case of where he could have a best case against each individual opponent, but not against multiple opponents at once.
So the next step is what I'm trying to do now. I'm not even sure I can give a good explanation without just showing you the entire spreadsheet w/script, but I'll try. So what I want to do now is calculate the "value" of each event for each player against a given other player. If both player and opponent assigned points in favor of the same event outcome for one event, the event's value is the difference between the picks (positive if player picked higher, negative if lower), and it's the SUM if they picked opposite event outcomes. Now, I do the same thing as before-- take a best-case scenario for a player against a given opponent-- but now I check by how much the player can beat the opponent in a best-case scenario. Then I evaluate the (absolute value of the) event value against this difference, and if it's greater, then the event is a must win (or must lose if the event value is negative). And, if an event is both a "must-win" and a "must lose" event, then the player is eliminated.
The problem is that this second step requires me to create a new array of values for each player-opponent combination, and then do things with the values after they're created.
I realize one approach would be to create 20 different arrays, and throughout the entire loops, keep checking "if (player == "1" && opponent == 2){}" and populate the arrays accordingly, but this seems kind of ridiculous. And more importantly, this entire project is my attempt at learning javascript, so what's the point in using a time-intensive workaround that doesn't teach me anything new?
I'm trying to understand square bracket notation, since it seems to be the answer to my question, but a lot of people are also suggesting that it's impossible to create variable names by concatenating with the value of another variable... so anyway, here's what I'm trying. I'd really appreciate either a fix to my approach, or a better approach.
for (var player=1; player<6; player++){
if(player==1){look up certain columns in the spreadsheet and save them to variables}
//ditto for other players
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
if(opponent==1){save more values to variables}
//ditto for other players
for(var row=9; row<24; row++) {
//Now the script goes down each row of an array containing the original
//spreadsheet info, and, based on information determined by the variables
//created above, get values corresponding to the player and opponent.
//So what I'd like to do here is create "array[1,2]==" and then "array[1,3]=="
//and so forth, creating them globally (I think I understand that term by now)
//so I can refer to them outside of the loops later to do some evaluatin'.
}
}}
//get array[1,2]...array[5,4] and do some operations with them.
Thanks for getting through this little novel... really looking forward to your advice and ideas!
How can I create arrays within a loop (within another loop)?
Code update 2
As you said: "i am trying to understand square bracket notation" You may take a look at my new demo and the code:
function getTeam(){
var array = [[1,2,3],[4,5,6],[7,8,9]]; // arrays within arrays
// array myTeam
var myTeam = [[],[],[],[]];
var playerNames = ["John", "Bert", "Dave", "Milton"];
var ages =[];
var weight = 104;
// loop over the team arrayadd each player (name, age and weight) to the team
for (i=0; i < myTeam.length; i++){
// fill the age array in a loop
for (j=0;j<myTeam.length;j++) {
ages[j] = 23 + j;
}
myTeam[i].push([playerNames[i], ages[i], weight]);
}
return myTeam;
}
And pass them back out in Javascript
Could you elaborate on this part?
Update
var valuesOfPlayers=[];
for (var player=1; player<6; player++){
// look up certain columns in the spreadsheet and save them to variables
// you could call a funcntion and return the values you
// collected in an array within an array as in the demo above
valuesOfPlayers[player] = lookupColumnValues(player);
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
// save more values to variables
valuesOfPlayers[player] = addValuesToVar(player);
}
for(var row=9; row<24; row++) {
// if you collect the values in your first and second if clause
// what other information do you want to collect
// Please elaborate this part?
}
}}
One workaround:
I could create an array before the execution of the loops.
At the start of each loop, I could push a string literal to the array containing the value of player and opponent.
After the loops are done, I could split the array into multiple arrays, or just evaluate them in one big array using regular expressions.
I'd still rather create new arrays each time-- seems like it is a more universal way of doing this, and learning how would be more educational for me than using this workaround.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
How have you explained nested arrays to a programmer. I'm thinking someone that has an entry level understanding of programming, but is trying to do more complicated coding.
The array with array works, but they can't quite get their mind around the idea.
Edit: example of a nested array:
array(
'array1' => array(
'key1' => 'val1',
'key2' => 'val2',
),
'array2' => array(
'key1' => 'val1',
'key2' => 'val2',
),
);
Of course, they are usually more complicated than this and maybe that's the problem.
Tell them to think of an array as a list- it helps to give them something less abstract, like a grocery list. Then, a nested array is simply a list of lists.
Maybe I have a todo list, a grocery list, and a wishlist at amazon.com . Now I have a list of all of my lists, and I can look at all of those elements in each list by stepping through them.
A nested array is a set within a set. So, a library has a set of books, a book has a set of chapters. A chapter has a set of paragraphs, a paragraph has a set of sentences. A sentence has a set of words.
For each book in library
For each chapter in book
For each paragraph in chapter
etc...
How have you explained it? It doesn't seem like a big jump for someone that understands one dimensional arrays to be able to grasp the concept that instead of an int or a string that each array element contains another array instead.
Perhaps an analogy comparing directories will help, a one dimensional array would be analogous to a directory that contains a bunch of files, a two-dimensional array to a directory which contains several other directories, each containing a bunch of files, etc.
Draw it.
A variable is a box
1 dimensional array is a row of boxes.
2 dimensional array is a grid of boxes.
3 dimensional array is a cube of boxes.
If they have having trouble with the general concept, don't attempt to visually explain 4 dimensions.
Use a bitmap as an example. In C, you can make a bitmap of an X like this:
int x[5][5] = {
{ 1,0,0,0,1 },
{ 0,1,0,1,0 },
{ 0,0,1,0,0 },
{ 0,1,0,1,0 },
{ 1,0,0,0,1 }
};
Then show them how to use nested for loops to display the bitmap.
Examples always help, and this also gets them to think of nested arrays as multi-dimensional arrays. Actually it's probably better to understand multi-dimensional arrays in a language like C before learning about the "nested" arrays in languages like Python where you can have different levels of nesting in the same array.
Sports can provide appropriate analogies to describe applying nested arrays. A team is an array of people, a competition is an array of teams that play against each other.
However its a case of finding the analogy that clicks with the learner. Find the right analogy and you'll get even the slowest of learners to understand. Just ensure you're analogies are water tight. Like abstractions, they are leaky.
A concrete example is the index at the back of a book. A list of words, each word associated with a list of page numbers.
apples - 1, 2, 3-4
bears - 32-35, 79, 83
cats - 14, 15
If you are looking at C type, non-ragged, arrays, comparing it to numbers, the base 10 part, and there digits might help. Another good source for this same effect would be time as it has a non uniform base 60s = 1m, 60m = 1h, 24h = 1day, 7day = 1week
2 dimensions is easy to explain. Just think of a table. 3 dimensions just think of a cube or other 3d image. 4 dimensions think of a series of images like a movie with the 4th dimension being time.
4+ dimensions is hard to visualize using that model. But think of it as a filing cabinet with another file cabinet inside helps. You open the drawer and out pops a filing cabinet. You find the drawer you want and open that drawer and out pops another filing cabinet....over and over until finally you get your paper.
Perhaps you are explaining it from the context of someone who understands an array of arrays. I would attempt to trick them into realizing that they already understand them by starting at the smallest(read inner array)...and slowly expanding out, giving them plenty of time to ask questions until they are done.
Drawing helps, but you need to give the student in this case some information and go slowly, most programmers I know tend to go to fast and to like to explain things EVEN when the listener no longer is tracking what is being said.
I am a metaphor guy, so I would probably cook something up about a series of boxes with each one numbered, each box then containing a similiar(but much smaller series) also numbered. I would take this to only two levels get understanding and then perhaps talk about 3 dimensions for confirmation. But I would avoid 4 dimensions on the grounds that they may get hung in the idea that there is no such thing as 4 dimensions, or you can't measure time, or other such metaphorical landmines/distractions...cause that's the other problem, programmers tend to be ADD and enjoy getting side tracked.
Also why aren't you using a hash of hashes, much easier to reference. :)
Bottom line, baby steps.
an array is just an object - a thing. everything should be simple to understand once they get that