How can I flatten an array swiftily in Swift? - arrays

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

Related

Append List of array to an array and repeat this in kotlin

I can't seem to find a right solution. Trying to add a list of array to another array. With my Python background it is easily done but not in Kotlin.
val extra = arrayOf(7,7,7)
fun containerArray() {
val even = arrayOf(2, 4, 6)
val odd = arrayOf(1, 3, 5)
val arr1 = arrayOf(even, odd)
val arr2 = arrayOf(*arr1, extra)
print(arr2.contentDeepToString())
}
fun main() {
for (i in 1..3) {
containerArray()
}
}
When executing above code I receive...
[[2, 4, 6], [1, 3, 5], [7, 7, 7]][[2, 4, 6], [1, 3, 5], [7,7,7]][...
What I want to achieve is this ....
[ [2, 4, 6], [1, 3, 5], [7, 7, 7], [7, 7, 7], [7, 7, 7]]
To add a thing to an array of things, and produce a new array, use plusElement:
val arr2 = arr1.plusElement(extra)
This not only works for arrays, but also works for any Iterables, i.e. Lists, Sets etc.
Do you get why you're getting that result? arrayOf(items) creates a new array wrapping those items, so arrayOf(even, odd) is an array that contains two arrays. Then you create another array, containing that array-of-arrays and another single array. You're nesting them as you go
Sweeper's answer is probably what you want, but there are a lot of ways to combine collections, flatten sequences etc. Like one thing you can do is use the *operator (the "spread operator") to "unpack" your arrays, so you get the items instead:
// unpack arr1 from an array of arrays, into just those arrays
// equivalent to arrayOf([2, 4, 6], [1, 3, 5], extra)
val arr2 = arrayOf(*arr1, extra)
print(arr2.contentDeepToString())
>> [[2, 4, 6], [1, 3, 5], [7, 7, 7]]
There's also flatMap, flatten etc - the best option depends on what you're doing!
Also when you say you want this:
[2, 4, 6], [1, 3, 5], [7, 7, 7]
that's just a bunch of values, not contained in anything, so we're assuming you want this:
[[2, 4, 6], [1, 3, 5], [7, 7, 7]]
where they're held in an array (or it could be a list). You could use the spread operator to unpack that into a bunch of values, but all you can do with that is pass it as a variable number of arguments to a function (which is what's happening in arrayOf)
I assume you want to get the following array:
[[2, 4, 6], [1, 3, 5], [7, 7, 7]]
There is an overridden + (plus) operator for Arrays in Kotlin, you can use it for adding arrays:
val arr2 = arr1 + extra
Resulting array arr2 will contain all elements of the original array arr1 and then all elements of the array extra.
ADDITIONALLY:
You can add another array to arr2:
val anotherArray = arrayOf(5, 5, 5)
val arr3 = arr2 + anotherArray
// result: [[2, 4, 6], [1, 3, 5], [7, 7, 7], [5, 5, 5]]
If you want to use the same array arr2 to store elements, you can create it with var modifier:
var arr2 = arr1 + extra
arr2 += arrayOf(5, 5, 5)
There are different ways of what you are trying to achieve using a loop, for example:
val even = arrayOf(2, 4, 6)
val odd = arrayOf(1, 3, 5)
val extra = arrayOf(7,7,7)
var arr1 = arrayOf(even, odd)
for (i in 1..3) {
arr1 += extra
}
arr1 will contain next elements: [[2, 4, 6], [1, 3, 5], [7, 7, 7], [7, 7, 7], [7, 7, 7]]

A simple "splice" type method on Array in Swift?

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>

Sum the elements of two equal count arrays [duplicate]

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]

Creating an array in Swift by applying binary operation to all elements of two other arrays

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]

Combine arrays in Ruby

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

Resources