Looking to add together integers from a dictionary. For example:
var dictionary = ["one": 1, "two": 2, "three": 3, "four": 4, "five": 5]
I would want to get the sum of 1+2+3+4+5 = 15
I understand it will probably need a loop something like
for (n, i) in dictionary {
*some math function*
}
any help would be appreciated maybe I'm just over thinking this one?
You can use reduce:combine: to get the sum.
With Swift 2.0, reduce:Combine: is added to the protocol extension of SequenceType. So, it is available to all SequenceType like Array, Set or Dictionary.
dictionary.reduce(0) {
sum, item in
return sum + item.1
}
item inside the closure is tuple representing each (key, value) pair. So, item.0 is key where as item.1 is value.The initial value of the sum is 0, and then each time the iteration takes place, sum is added to the value extracted from dictionary.
You could also write it in short as,
dictionary.reduce(0) { return $0 + $1.1 }
While older version of Swift, it has reduce method with Array only. So, we could first get array and apply reduce:combine to get the sum as,
let a = dictionary.values.array.reduce(0) { return $0 + $1 }
Related
How to put the same, but positive, before each negative element of the array. Count the number of inserted elements
example:
var arrayInt: [Int] = [22, 16, -39, 1, -200]
result: [22, 16, 39, -39, 1, 200, -200]
what to use for-in or method .map or method .filter
Thanks for the help!
Here's a relatively simple implementation:
let result: [Int] = arrayInt.reduce(into: []) { acc, item in
if item < 0 {
acc.append(-item)
}
acc.append(item)
}
reduce allows you to transform an array into an arbitrary type. In this case, you still want an [Int], but you don't want to be constrained to the same number of elements (like map would do).
If you need the number of inserted elements:
let inserted = result.count - arrayInt.count
Note that you could also build this into the result by returning a tuple with a count instead of just an [Int]
Keep in mind this is not the only possible solution -- just a relatively straightforward one.
In response to the comments, you could also turn this into a one-liner with something like flatMap: arrayInt.flatMap { $0 < 0 ? [-$0, $0] : [$0] }
In Swift, is it possible to enumerate a sequence starting at 1?
In my case, I'm using the SQLite C interface to bind values to prepared statements. The second argument of the sqlite3_bind_*() routines is the index of the SQL parameter to be set. The indices start at 1. (Ie, they're one-based.)
I could use Sequence.enumerated() and just add 1 to n inside each iteration, like so:
for (n, value) in values.enumerated() {
sqlite3_bind_int(stmt, Int32(n)+1, value)
}
But is there a way to start n from 1?
No, all collections indices in Swift are zero based but if you really want you can create your own custom enumeration zipping a range of Int32 values and the source collection:
extension Collection {
var enumerated: Zip2Sequence<PartialRangeFrom<Int32>, Self> { zip(1..., self) }
}
usage:
let values: [Int32] = [10, 20, 30]
for (n, value) in values.enumerated {
print("value:", value, "at:", n)
}
This will print
value: 10 at: 1
value: 20 at: 2
value: 30 at: 3
As others have said, array indexes start at 0 in Swift, so if you want to have 1-based indexes out of the box, you'll need to write some extra code.
If you're only using the index once then any workarounds might not worth the effort, and the incrementing at the call site is the most straightforward solution.
If however you will need to use the incremented index multiple times within the loop, another approach you could take would be to shadow the index:
for (n, element) in [1, 2,3].enumerated() {
let n = n + 1
sqlite3_bind_int(stmt, Int32(n), value)
}
Another approach could be using map():
for (n, element) in [1, 2,3].enumerated().map({($0+1,$1)}) {
sqlite3_bind_int(stmt, Int32(n), value)
}
, however not sure if you gain much with this solution, as the code is a little bit obscure.
I am trying to create a function that takes an array of Int, and returns a new array of all of the even numbers in the original array.
I have been fumbling around with this code (I am a very new beginner)
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray: [Int] = []
func newInt(newEven: Int, newArray: [Int]) -> Int {
for newEven in numberArray{
var index = 0
index += 1
if newEven % 2 == 0 {
newArray.insert(newEven, at:[index])
}
return newEven
}
}
print(newArray)
This is a good start! Here are some pointers:
1. Formatting
The formatting needs some work. Generally, every new scope ({ ... }) should introduce a new layer of indentation, like so:
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray: [Int] = []
func newInt(newEven: Int, newArray: [Int]) -> Int {
for newEven in numberArray{
var index = 0
index += 1
if newEven % 2 == 0 {
newArray.insert(newEven, at:[index])
}
return newEven
}
}
print(newArray)
Now we can make some observations:
1. index is scoped to the for loop body, and will always have the same value of 0, and then 1 after the next line.
2. The return statement is within the for loop body, and unconditional. This function will always return the value of the first element of numberArray
3. The return type of this function is Int. But in your question, you state that you want this to return an array of all of the even numbers. So your return type will have to be Array<Int> (a.k.a. [Int]), not just Int.
2. Compilation issues
This function has several errors that will prevent compilation:
The return statement is within a loop body. If numberArray is empty, and the for loop body is never entered, then you don't hit the return statement. Once control reaches the end of the function, what value should be returned? It's not defined, so that's an error. In Swift, all code paths through a function must return a value. (with the exception of Void functions, which implicitly return nothing at the end)
You're trying to call Array.insert(_:at:) with a second argument of [index], which is an array literal of type Array<Int>. It should just be index.
3. Logical issues
Your function introduces a parameter called newArray, which shadows the global variable newArray on the line before it. The global variable isn't necessary, and you should delete it.
Your function operates over numberArray, but doesn't explicitly take it as input via a parameter. Rather than hardcoding a reference to a global variable like numberArray, you should use a parameter.
The parameter newEven is unused, and is shadowed by the local variable of the for loop
Your function name newInt(newEven:newArray:) doesn't describe what the function does. Consider a function signature like func allEvens(in input: [Int]) -> [Int]
You never actually call this function. You declare it, but never told the program to run it.
You don't need to use Array.insert(_:at:). You can simply use Array.append, which will automatically append elements to the end of the array.
4. Recommendations
Fix the method signature. You want the function to take some numbers, and output only the even numbers. Model that in code: func allEvens(in input: [Int]) -> [Int]
Create a new empty array locally (within the function), into which the even numbers will be stored. As you loop over the input array, check every number if it's even, and if so, append it to the evens array.
Return the evens array.
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray = numberArray.filter({$0 % 2 == 0})
This should return a new array with even numbers.
As LeoDabus mentioned in his comment, the functionality you're seeking is already contained within Swift's Standard Library, so it's not really necessary to write a dedicated function to accomplish that task. Here's how you would do it:
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let newArray = numberArray.filter { $0.isMultiple(of: 2) }
print(newArray) // [2, 4, 6, 8, 10]
In this, you're using the filter whether $0 (where $0 is an element in your array) is a multiple of the number you specified in the parameter, in this case, 2.
As you see in the documentation, isMultiple(of:) returns a Bool (true or false). This is the signature:
func isMultiple(of other: Self) -> Bool
I would recommend having a peek at this post covering the topics of map, filter, and reduce. These are useful things to know when starting out in Swift.
Additionally, I've found Dash to be extremely helpful in navigating documetation for Swift.
Update
I should have read your question more thoroughly, as I missed the part where you've gotta do it with a loop. Swift has a cool method called forEach, which I'm a huge fan of. Using that methodology, it would look something like this:
func filter(array: [Int], forMultiplesOf multiple: Int) -> [Int] {
// Create a landing spot for whatever is a multiple...it starts as empty
var newArray: [Int] = []
// This is not the most compact way, but it satisfies the loop constraint
array.forEach { number in
if number % multiple == 0 {
newArray.append(number)
}
}
// Once you're done with the loop, then return the new array you declared at the beginning
return newArray
}
And you'd call it like so:
let newArrayUsingFunction = filter(array: numberArray, forMultiplesOf: 2)
What you're doing here is passing in 2 parameters to the function (array & multiple) to return an array of Ints. See comments in code for what's going on
I would like to be able to find the nearest smaller value in an array of numbers. For instance, if I have:
[1, 4, 6, 9, 14, 39]
And I'm looking for the nearest value smaller than:
8
The function would return:
6
Additionally, if I pass a number greater than the maximum value in the array, it should return the maximum. If I pass a number smaller than the minimum, it should return nil.
I tried doing this using the first function on arrays, however this on its own doesn't produce the result I'm looking for as I would need something like this:
numbers.first(where: { $0 <= target && $1 < target })
but unfortunately, this isn't valid. Any suggestions? I know this could be done fairly trivially with a while loop, however I was hoping there would be a cleaner, functional way.
Given that the array is sorted , You need
if let value = numbers.last(where: { $0 <= target }) {
print(value)
}
This is a generic solution using binary search. The array must be sorted
extension RandomAccessCollection where Element : Comparable {
func lowerElement(of value: Element) -> Element? {
var slice : SubSequence = self[...]
while !slice.isEmpty {
let middle = slice.index(slice.startIndex, offsetBy: slice.count / 2)
if value < slice[middle] {
slice = slice[..<middle]
} else {
slice = slice[index(after: middle)...]
}
}
return slice.startIndex == self.startIndex ? nil : self[self.index(before: slice.startIndex)]
}
}
let array = [1, 4, 6, 9, 14, 39]
let result = array.lowerElement(of: 8)
print(result)
In Swift arrays you can do:
var myArray = [1,2,3,4]
myArray.forEach() { print($0 * 2) }
myArray.map() { print($0 * 2) }
They both do the same thing. The only difference is .map also returns an array of voids as well, [(),(),(),()], which gets unused. Does that mean .map performs worse than .forEach when it's not assigning to anything?
In Swift as per Apple's definition,
map
is used for returning an array containing the results of mapping the
given closure over the sequence’s elements
whereas,
forEach
calls the given closure on each element in the sequence in the same
order as a for-in loop.
Both got two different purposes in Swift. Even though in your example map works fine, it doesn't mean that you should be using map in this case.
map eg:-
let values = [1.0, 2.0, 3.0, 4.0]
let squares = values.map {$0 * $0}
[1.0, 4.0, 9.0, 16.0] //squares has this array now, use it somewhere
forEach eg:-
let values = [1.0, 2.0, 3.0, 4.0]
values.forEach() { print($0 * 2) }
prints below numbers. There are no arrays returned this time.
2.0
4.0
6.0
8.0
In short to answer your questions, yes the array generated from map is wasted and hence forEach is what you should use in this case.
Update:
OP has commented that when he tested, the performance was better for map compared to forEach. Here is what I tried in a playground and found. For me forEach performed better than map as shown in image. forEach took 51.31 seconds where as map took 51.59 seconds which is 0.28 seconds difference. I don't claim that forEach is better based on this, but both has similar performance attributes and which one to use, depends on the particular use case.
According to Apple Doc
.map
The map(_:) method calls the closure expression once for each item in
the array. You do not need to specify the type of the closure’s input
parameter, number, because the type can be inferred from the values in
the array to be mapped.
.forEach(_:)
Apple Doc
Calls the given closure on each element in the sequence in the same
order as a for-in loop.
var myArray = [1,2,3,4]
var sampleArray = [1,2,3,4]
//myArray = myArray.forEach() { ($0 * 2) }//Not allowed
sampleArray = sampleArray.map() { ($0 * 2) }
print("sampleArray array is \(sampleArray)")//sampleArray array is [2, 4, 6, 8]
.map is faster than .forEach.
Just by a hair. Note that assigning .map to _ as pictured causes the closure to be required not to return a value.
A wild compiler optimization appears!