Related
I'm looking for an elegant way to select a range of elements in an Array to remove and return, mutating the original array. Javascript has a splice method that serves this purpose but I can't seem to find anything baked into Swift to achieve both steps:
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let oneTwoThree = array.removeAndReturn(0...2) // [1, 2, 3]
// array == [4, 5, 6, 7, 8, 9, 10]
I know about dropFirst(:), prefix(:) and removeSubrange(:) but they all either only return values without mutating the original array, or they mutate the original array without returning values.
Is there another baked-in method I've missed, or would I have to implement a custom extension/method to make this work?
There are removeFirst(), removeLast() and remove(at:) methods which remove
and return a single collection element, but no similar method to remove and return a subrange, so you'll have to implement your own.
A possible implementation is
extension RangeReplaceableCollection {
mutating func splice<R: RangeExpression>(range: R) -> SubSequence
where R.Bound == Index {
let result = self[range]
self.removeSubrange(range)
return result
}
}
Examples:
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8]
print(a.splice(range: 3...4), a) // [3, 4] [0, 1, 2, 5, 6, 7, 8]
print(a.splice(range: ..<2), a) // [0, 1] [2, 5, 6, 7, 8]
print(a.splice(range: 2...), a) // [6, 7, 8] [2, 5]
var data = Data(bytes: [1, 2, 3, 4])
let splice = data.splice(range: 2...2)
print(splice as NSData) // <03>
print(data as NSData) // <010204>
I'd like to save in two variables the values of an array excluding the first and last elements.
For example:
prices = [9, 3, 5, 2, 1]
The elements I need are:
prices_excl_first = [3, 5, 2, 1]
prices_excl_last = [9, 3, 5, 2]
I figured out how to remove an element from an array a few ways, including slicing off the value by passing its index to the slice method like so:
first_price = prices.slice(0)
last_price = prices.slice(-1)
We could then save the modified arrays into variables:
array_except_first_price = prices.delete(first_price) #=> [3, 5, 2, 1]
array_except_last_index = prices.delete(last_price) #=> [3, 5, 2]
There are two problems with this:
array_except_last_index doesn't contain the first element now
I still need access to the full, original array prices later
So essentially, how can I just temporarily modify the elements in the array when necessary in the problem?
Slicing and dropping elements from array permanently affect the array.
Ruby has first and last to copy just the first and last elements.
Ask for the first and last prices.size-1 elements.
prices = [9, 3, 5, 2, 1]
except_first = prices.last(prices.size-1)
except_last = prices.first(prices.size-1)
#Schwern's answer is probably the best you can get. Here's the second best:
prices = [9, 3, 5, 2, 1]
prices[1..-1] # => [3, 5, 2, 1]
prices[0..-2] # => [9, 3, 5, 2]
Or drop/take (which more closely map to the wording of your question).
prices.drop(1) # => [3, 5, 2, 1]
prices.take(prices.size-1) # => [9, 3, 5, 2]
You could use each_cons:
a, b = prices.each_cons(prices.size - 1).to_a
a #=> [9, 3, 5, 2]
b #=> [3, 5, 2, 1]
Splat it.
*a, d = prices
c, *b = prices
a #=> [9, 3, 5, 2]
b #=> [3, 5, 2, 1]
You can use dup to duplicate the array before performing destructive operations.
prices = [9, 3, 5, 2, 1]
except_first = prices.dup
except_first.delete_at 0
except_last = prices.dup
except_last.delete_at -1
This does end up duplicating the array a couple of times. If you're dealing with large arrays, this may be a problem.
Is there a concise way in Swift of creating an array by applying a binary operation on the elements of two other arrays?
For example:
let a = [1, 2, 3]
let b = [4, 5, 6]
let c = (0..<3).map{a[$0]+b[$0]} // c = [5, 7, 9]
If you use zip to combine the elements, you can refer to + with just +:
let a = [1, 2, 3]
let b = [4, 5, 6]
let c = zip(a, b).map(+) // [5, 7, 9]
Update:
You can use indices like this:
for index in a.indices{
sum.append(a[index] + b[index])
}
print(sum)// [5, 7, 9]
(Thanks to Alexander's comment this is better, because we don't have to deal with the element itself and we just deal with the index)
Old answer:
you can enumerate to get the index:
var sum = [Int]()
for (index, _) in a.enumerated(){
sum.append(a[index] + b[index])
}
print(sum)// [5, 7, 9]
I want to turn this:
let x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
into this:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
very gracefully.
The most straightforward way, of course, is
var y = [Int]()
x.forEach { y.appendContentsOf($0) }
But that makes the resulting array mutable, which is unnecessary. I don't like this way.
I tried using reduce:
let y = x.reduce([Int]()) { (array, ints) -> [Int] in
array.appendContentsOf(ints)
return array
}
But the compiler complains that array is immutable, so I can't call the mutating method appendContentsOf.
Hence, I added some stuff:
let y = x.reduce([Int]()) { (array, ints) -> [Int] in
var newArr = array
newArr.appendContentsOf(ints)
return newArr
}
This is just plain bad. I have an instinct that this is not swifty.
How can I flatten an array more swiftily than the above methods? A one-liner would be good.
There's a built-in function for this called joined:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]].joined()
(Note that this doesn't actually return another Array, it returns a FlattenSequence, but that usually doesn't matter because it's still a sequence that you can use with for loops and whatnot. If you really care, you can use Array(arrayOfArrays.joined()).)
The flatMap function can also help you out. Its signature is, roughly,
flatMap<S: SequenceType>(fn: (Generator.Element) -> S) -> [S.Generator.Element]
This means that you can pass a fn which for any element returns a sequence, and it'll combine/concatenate those sequences.
Since your array's elements are themselves sequences, you can use a function which just returns the element itself ({ x in return x } or equivalently just {$0}):
[[1, 2, 3], [4, 5, 6], [7, 8, 9]].flatMap{ $0 }
With Swift 5, you can choose one of the three following ways in order to flatten an array.
#1. Flatten an array with Array's flatMap(_:) method
With Swift, types that conform to Sequence protocol (including Array) have a flatMap(_:) method. Array's flatMap(_:) has the following declaration:
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.
The Playground sample code below shows how to flatten an Array of type [[Int]] to type [Int] using flatMap(_:):
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let flattenArray = array.flatMap({ (element: [Int]) -> [Int] in
return element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6, 7, 8, 9]
#2. Flatten an array with Array's joined() method
Array's has a method called joined(). joined() has the following declaration:
func joined() -> FlattenSequence<Array<Element>>
Returns the elements of this sequence of sequences, concatenated.
The following Playground sample code shows how to flatten an Array of type [[Int]] to type [Int] using joined():
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let flattenCollection = array.joined()
let flattenArray = Array(flattenCollection)
print(flattenArray) // prints [1, 2, 3, 4, 5, 6, 7, 8, 9]
#3. Flatten an array with Array's reduce(_:_:) method
Swift Array has a reduce(_:_:) method with the following declaration:
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
Returns the result of combining the elements of the sequence using the given closure.
The following Playground sample code shows how to flatten an Array of type [[Int]] to type [Int] using reduce(_:_:):
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let flattenArray = array.reduce([], { (result: [Int], element: [Int]) -> [Int] in
return result + element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6, 7, 8, 9]
As an alternative to reduce(_:_:), you can use reduce(into:_:):
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let flattenArray = array.reduce(into: [Int]()) { (result: inout [Int], element: [Int]) in
result += element
}
print(flattenArray) // prints [1, 2, 3, 4, 5, 6, 7, 8, 9]
You only need to use 2 function to do that
joined()
compactMap
let y = x.compactMap{$0}.joined().compactMap{$0}
Reference for more about FlattenSequence
Flatten function in Array :
let x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let y = Array(x.flatten())
print(y)
flatMap function in Array :
let x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let y = x.flatMap({$0})
print(y)
Your Output :
For more : Array in Swift
I have two arrays as in the listing given below.
a = [1, 2, 3, 4, 5]
b = [1.360, 0.085, -1.190, -0.340, 3.698]
I need to merge the values at each index so that I get a structure resembling Resultant Array.
Resultant Array = [[1, 1.360], [2, 0.085], [3, -1.190], [4, -0.340], [5, 3.698]]
How do I go about doing it?
You can use Array#zip
a.zip(b)
# => [[1, 1.36], [2, 0.085], [3, -1.19], [4, -0.34], [5, 3.698]]
a = [1, 2, 3, 4, 5]
b = [1.360, 0.085, -1.190, -0.340, 3.698]
You can also try an alternative:
[a,b].transpose
Note: Use this when length of your array is same
You can do:
a.zip(b) #=> [[1,1.360],[2,0.085],[3,-1.190],[4,-0.340],[5,3.698]]
I didn't try it.
Source: apidoc.com