Will DeBernardi
Will DeBernardi

Reputation: 41

What is the best way to append an array using for in loop in Swift?

I am currently attempting to learn how to code swift via treehouse.com and so far I am enjoying it. I just came to my first "code challenge" as they call it that I somewhat struggled on. As the title suggested, the started with an empty array as such:

var results: [Int] = []

That is fine and dandy. The goal is to then write a for in loop which finds the multiples of 6 for the numbers 1-10 and then to append those values to the array. I eventually did figure it out, but I am not sure that I did it in the ideal way. I'd appreciate any criticism. My code will be included below. Do bear in mind that I am a total beginner to Swift and to coding in general. Thanks in advance for any suggestions/tips.

var results: [Int] = []
for multiplier in 1...10 {
    let multiples = (multiplier * 6)
    print(multiples)
    results.append(multiples)
}

The code executes properly and the array is appended with the values, but again, I am unsure if there is a better way to do this.

Upvotes: 4

Views: 9848

Answers (2)

Nirav D
Nirav D

Reputation: 72450

For your first question, Is there batter way or best way to append objects in array in for in loop is already explain by @Alexander, But if check properly he is still at last doing the same way you are doing the difference is only that he has specified the capacity of array, So the way you are appending object in array is look like perfect but for that you need to write to much code.

Now to reduce your code and do what you are currently doing in a Swifty way you can use built in map function for that.

let result = (1...10).map { $0 * 6 }
print(result) // [6, 12, 18, 24, 30, 36, 42, 48, 54, 60]

First (1...10) will create CountableClosedRange after that we are calling map(_:) closure with it. Now map will sequentially take each element from this CountableClosedRange. So $0 will take each argument from CountableClosedRange. Now we are multiplying that element with 6 and returning the result from the closure and generate the result according to its return value in this case it will create Array of Int.

Upvotes: 11

Alexander
Alexander

Reputation: 63349

This is a great question, and a perfect opportunity to explain map and array reallocation costs.

Arrays have two important properties you need to understand.

  • The first is their count. The count is simply the number of items in the array.

  • The other is the capacity. The capacity is the number of elements that can fit the memory that has been allocated for this array. The capacity is always ≥ the count (d'uh!).

When you have an Array of say, capacity 10, and count 5, and you try to append to it, you can do that right away. Set the 6th element to the new value, and boom, you're done instantly.

Now, what happens if you have an Array of capacity 10, and count 10, and you try to append to it? Well there's no more room for new elements given the memory the array currently has allocated. What needs to happen is that the Array has to ask the operating system for a new chunk of memory that has a capacity that's high enough to fit at least the existing elements, plus the new incoming element. However, this new chunk of memory is empty, so we need to copy over what we had in our old small chunk of memory, before we can do the append. Suppose our new chunk has capacity 20, and we copy our 10 old elements. We can now add in our new element in the 11th slot.

Notice we had to copy the elements from our old memory into the new memory. Well if our count is 10, that's 10 copy operations. This means that appending to an array that's at capacity is much slower than appending an array with available capacity.

Suppose we go on to add another 1000 elements. - Our array will fill its new memory at count 20, so it'll need to reallocate a new piece of memory, do 20 copy operations. Suppose this new piece of memory has capacity 40. - Our array will fill its new memory at count 40, so it'll need to reallocate a new piece of memory, do 40 copy operations. Suppose this new piece of memory has capacity 80. - This process will repeat at count = 80, 160, 320, 640, until we finally have all 1011 elements in our array of capacity 1280. This took 10 + 20+ 40 + 80 + 160 + 320 + 640 = 1270 copy operations in total!

What if we were smart about this, and knew in advance that we were about to add 1000 items, and could tell the array to resize itself all at once, to fit our new 1000 items?

Well we can do exactly that, with reserveCapacity(_:). It lets us tell the array to allocate a certain capacity for us, rather than it having to constantly resize on-demand as we keep stuffing it. Using this technique, we can ensure now copy operations occur at all!

Now let's apply that to your code. We can rewrite it like so, to ensure no array reallocaitons happen (even it 1...10 were something higher, like 1...10000000)

let numbers = 1...10
let numberCount = numbers.count

var products = [Int]()
products.reserveCapacity(numberCount)
for number in numbers {
    let product = (number * 6)
    print(product)
    products.append(product)
}

Now all that is quite a bit of code, for such a simple operation. It's also a pretty common operation. This is why map exists, to simplify all this.

map(_:) takes a closure which tells it what to do to each element. map(_:) will take every element in your sequence (in this case, your CountableClosedRange<Int>, 0...10, but it can be an Array, or any other Sequence), run it through your closure to produce some result, and put the result in the final array.

Internally, map(_:) works very similar to the code you wrote above. It creates a mutable array, reserves enough capacity for all the elements, and runs a for loop which repeatedly appends to that array. The nice thing is that it hides all this logic from you, so all you have to see is this really simple statement:

let produces = (1...10).map{ $0 * 6 }

Closures are explained simply, and in great detail in the Swift Progamming Language Guide. I suggest you take a look when you have a chance!

Upvotes: 7

Related Questions