Related
I have an array of elements (numbers in my case)
var myArray= Array(1, 2, 3, 4, 5, 6)
//myArray: Array[Int] = Array(1, 2, 3, 4, 5, 6)
and I want to obtain a tuple than contain all of them:
var whatIwant= (1,2,3,4,5,6)
//whatIwant: (Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6)
I tried the following code but it doesn't work:
var tuple = myArray(0)
for (e <- myArray)
{
var tuple = tuple :+ e
}
//error: recursive variable tuple needs type
The trivial answer is this:
val whatIwant =
myArray match {
case Array(a, b, c, d, e, f) => (a, b, c, d, e, f)
case _ => (0, 0, 0, 0, 0, 0)
}
If you want to support different numbers of element in myArray then you are in for a world of pain because you will lose all the type information associated with a tuple.
If you are using Spark you should probably use its mechanisms to generate the data you want directly rather than converting to Array first.
The number of elements of a tuple is not infinitely superimposed. In earlier versions, there were only 22 at most. Scala treats tuples with different numbers of elements as different classes. So you can't add elements like a list.
Apart from utilizing metaprogramming techniques such as reflection, tuple objects may only be generated explicitly.
var number: [Int] = [1,2,3,4]
var newArray: [Int] = []
for i in 0...number.count-1{
newArray = number[i] * number[i+1]
}
print(newArray)
I want output like this: [1 * 2, 2 * 3, 3 * 4].
I just don't get it where is the problem...
var number: [Int] = [1,2,3,4]
let things = zip(number, number.dropFirst()).map(*)
Whenever you need to turn something like [1, 2, 3, 4] into pairs (1, 2), (2, 3) etc, then the AdjacentPairs method is useful - in Swift Algorithms package - https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/AdjacentPairs.swift
Or you can zip a collection with its dropFirst for the same result.
And whenever you need to turn an [A]s into an [B]s then map with a function that turns As into Bs. So in this example you want to turn an array of tuples of Int, like [(1,2), (2,3), (3,4)] into array of Int, like [2, 6, 12] by multiplying the 2 Ints together, so map with *
The benefit of writing it this way is you would avoid the issues with your array mutation, getting index values wrong, running off the ends of arrays etc, and it's often easier to read and think about if you express it without the indices and assignments.
The problem that the compiler flags you is that you assign a single Int value to an array of Int. The following line will resolve that immediate issue:
newArray.append(number[i] * number[i+1])
This should pass compilation but then create a runtime error at execution. The reason is that when you try to fetch number[i+1] when i == number.count-1, you actually fetch number[number.count]. This entry does not exist with 0-based indices. To get 3 sums out of 4 array entries, your loop should iterate 3 times:
for i in 0 ..< number.count-1 {
Or, if you prefer closed ranges:
for i in 0 ... number.count-2 {
A more Swifty way would be to use map, as #Dris suggested. The return type for map is implicitly given by the result of the multiplication, so you can write:
let newArray = number.indices.dropLast().map { i in
number[i] * number[i+1]
}
You can use map()
let numbers = [1,2,3,4]
let newArray = numbers.enumerated().map { $1 * numbers[($0 + 1) % numbers.count] }
May be you should not loop to count-1 but stop before and add result to array :
for i in 0..<number.count-1 {
newArray.append(number[i] * number[i+1])
}
I have a flat array like this and another flat array that describes the dimensions:
val elems = Array(0,1,2,3)
val dimensions = Array(2,2)
So now I must be able to unflatten that and return a 2*2 array like this:
val unflattened = {{0,1},{2,3}}
The dimensions could be of any order. The only condition is that the length of the flat array will equal to the product of the dimensions. So for example., if the dimensions is
Array(3,3)
then I expect that the elems flat array will have to have 9 elements in it! The preconditions will be checked elsewhere so I do not have to worry about it here! All I need to do is to return an unflattened array.
Since this has to work on any dimension size, I think I probably have to define a recursive structure to put my results! Something like this?
case class Elem(elem: Array[Elem])
Could this work?
Any clue on how to go about implementing this function?
Although you should be able to do this with a simple recursive structure, I went along with a structure more suited to the problem.
case class Row(elems: List[Int])
trait Matrix
case class SimpleMatrix(rows: List[Row]) extends Matrix
case class HigherMatrix(matrices: List[Matrix]) extends Matrix
// since your flat arrays are always of proper sizes... we are not handling error cases
// so we are dealing with higher N-dimension matrices with size List(s1, s2, ...,sN)
// I have chosen List for the example (as its easy to print), you should choose Array
def arrayToMatrix(flat: List[Int], dimension: Int, sizes: List[Int]): Matrix = dimension match {
case 1 | 2 =>
// since your flat arrays are always of proper sizes... there should not be any problems here
SimpleMatrix(
flat
.grouped(sizes.head)
.map(Row)
.toList
)
case _ =>
HigherMatrix(
flat
.grouped(sizes.tail.reduce(_ * _))
.map(g => arrayToMatrix(g, dimension - 1, sizes.tail))
.toList
)
}
def arrayToSquareMatrix(flat: List[Int], dimension: Int, size: Int): Matrix =
arrayToMatrix(flat, dimension, Range.inclusive(1, dimension).map(_ => size).toList)
Here are the examples
val sm_2__2_2 = arrayToSquareMatrix(Range.inclusive(1, 4).toList, 2, 2)
// sm_2__2_2: Matrix = SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4))))
val m_2__3_2 = arrayToMatrix(Range.inclusive(1, 6).toList, 2, List(3, 2))
// m_2__3_2: Matrix = SimpleMatrix(List(Row(List(1, 2, 3)), Row(List(4, 5, 6))))
val sm_3__2_2_2 = arrayToSquareMatrix(Range.inclusive(1, 8).toList, 3, 2)
// sm_3__2_2_2: Matrix = HigherMatrix(List(SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4)))), SimpleMatrix(List(Row(List(5, 6)), Row(List(7, 8))))))
val m_3__3_2_2 = arrayToMatrix(Range.inclusive(1, 12).toList, 3, List(3, 2, 2))
// m_3__3_2_2: Matrix = HigherMatrix(List(SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4)))), SimpleMatrix(List(Row(List(5, 6)), Row(List(7, 8)))), SimpleMatrix(List(Row(List(9, 10)), Row(List(11, 12))))))
Here is a solution:
def unflatten(flat: Vector[Any], dims: Vector[Int]): Vector[Any] =
if (dims.length <= 1) {
flat
} else {
val (Vector(dim), rest) = dims.splitAt(1)
flat.grouped(flat.length/dim).map(a => unflatten(a, rest)).toVector
}
I have used Vector because Array isn't really a Scala type and doesn't allow conversion from Array[Int] to Array[Any].
Note that this implements only one of the possible partitions with the given dimensions, so it may or may not be what is required.
This is a version using types based on the Matrix trait in another answer:
trait Matrix
case class SimpleMatrix(rows: Vector[Int]) extends Matrix
case class HigherMatrix(matrices: Vector[Matrix]) extends Matrix
def unflatten(flat: Vector[Int], dims: Vector[Int]): Matrix =
if (dims.length <= 1) {
SimpleMatrix(flat)
} else {
val (Vector(dim), rest) = dims.splitAt(1)
val subs = flat.grouped(flat.length/dim).map(a => unflatten(a, rest)).toVector
HigherMatrix(subs)
}
There is a function grouped on Arrays which does what you want.
# Array(0,1,2,3).grouped(2).toArray
res2: Array[Array[Int]] = Array(Array(0, 1), Array(2, 3))
I'm curious about the performance characteristics of joined() and .flatMap(_:) in flattening a multidimensional array:
let array = [[1,2,3],[4,5,6],[7,8,9]]
let j = Array(array.joined())
let f = array.flatMap{$0}
They both flatten the nested array into [1, 2, 3, 4, 5, 6, 7, 8, 9]. Should I prefer one over the other for performance? Also, is there a more readable way to write the calls?
TL; DR
When it comes just to flattening 2D arrays (without any transformations or separators applied, see #dfri's answer for more info about that aspect), array.flatMap{$0} and Array(array.joined()) are both conceptually the same and have similar performance.
The main difference between flatMap(_:) and joined() (note that this isn't a new method, it has just been renamed from flatten()) is that joined() is always lazily applied (for arrays, it returns a special FlattenBidirectionalCollection<Base>).
Therefore in terms of performance, it makes sense to use joined() over flatMap(_:) in situations where you only want to iterate over part of a flattened sequence (without applying any transformations). For example:
let array2D = [[2, 3], [8, 10], [9, 5], [4, 8]]
if array2D.joined().contains(8) {
print("contains 8")
} else {
print("doesn't contain 8")
}
Because joined() is lazily applied & contains(_:) will stop iterating upon finding a match, only the first two inner arrays will have to be 'flattened' to find the element 8 from the 2D array. Although, as #dfri correctly notes below, you are also able to lazily apply flatMap(_:) through the use of a LazySequence/LazyCollection – which can be created through the lazy property. This would be ideal for lazily applying both a transformation & flattening a given 2D sequence.
In cases where joined() is iterated fully through, it is conceptually no different from using flatMap{$0}. Therefore, these are all valid (and conceptually identical) ways of flattening a 2D array:
array2D.joined().map{$0}
Array(array2D.joined())
array2D.flatMap{$0}
In terms of performance, flatMap(_:) is documented as having a time-complexity of:
O(m + n), where m is the length of this sequence and n is the length of the result
This is because its implementation is simply:
public func flatMap<SegmentOfResult : Sequence>(
_ transform: (${GElement}) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.${GElement}] {
var result: [SegmentOfResult.${GElement}] = []
for element in self {
result.append(contentsOf: try transform(element))
}
return result
}
}
As append(contentsOf:) has a time-complexity of O(n), where n is the length of sequence to append, we get an overall time-complexity of O(m + n), where m will be total length of all sequences appended, and n is the length of the 2D sequence.
When it comes to joined(), there is no documented time-complexity, as it is lazily applied. However, the main bit of source code to consider is the implementation of FlattenIterator, which is used to iterate over the flattened contents of a 2D sequence (which will occur upon using map(_:) or the Array(_:) initialiser with joined()).
public mutating func next() -> Base.Element.Iterator.Element? {
repeat {
if _fastPath(_inner != nil) {
let ret = _inner!.next()
if _fastPath(ret != nil) {
return ret
}
}
let s = _base.next()
if _slowPath(s == nil) {
return nil
}
_inner = s!.makeIterator()
}
while true
}
Here _base is the base 2D sequence, _inner is the current iterator from one of the inner sequences, and _fastPath & _slowPath are hints to the compiler to aid with branch prediction.
Assuming I'm interpreting this code correctly & the full sequence is iterated through, this also has a time complexity of O(m + n), where m is the length of the sequence, and n is the length of the result. This is because it goes through each outer iterator and each inner iterator to get the flattened elements.
So, performance wise, Array(array.joined()) and array.flatMap{$0} both have the same time complexity.
If we run a quick benchmark in a debug build (Swift 3.1):
import QuartzCore
func benchmark(repeatCount:Int = 1, name:String? = nil, closure:() -> ()) {
let d = CACurrentMediaTime()
for _ in 0..<repeatCount {
closure()
}
let d1 = CACurrentMediaTime()-d
print("Benchmark of \(name ?? "closure") took \(d1) seconds")
}
let arr = [[Int]](repeating: [Int](repeating: 0, count: 1000), count: 1000)
benchmark {
_ = arr.flatMap{$0} // 0.00744s
}
benchmark {
_ = Array(arr.joined()) // 0.525s
}
benchmark {
_ = arr.joined().map{$0} // 1.421s
}
flatMap(_:) appears to be the fastest. I suspect that joined() being slower could be due to the branching that occurs within the FlattenIterator (although the hints to the compiler minimise this cost) – although just why map(_:) is so slow, I'm not too sure. Would certainly be interested to know if anyone else knows more about this.
However, in an optimised build, the compiler is able to optimise away this big performance difference; giving all three options comparable speed, although flatMap(_:) is still fastest by a fraction of a second:
let arr = [[Int]](repeating: [Int](repeating: 0, count: 10000), count: 1000)
benchmark {
let result = arr.flatMap{$0} // 0.0910s
print(result.count)
}
benchmark {
let result = Array(arr.joined()) // 0.118s
print(result.count)
}
benchmark {
let result = arr.joined().map{$0} // 0.149s
print(result.count)
}
(Note that the order in which the tests are performed can affect the results – both of above results are an average from performing the tests in the various different orders)
From the Swiftdoc.org documentation of Array (Swift 3.0/dev) we read [emphasis mine]:
func flatMap<SegmentOfResult : Sequence>(_: #noescape (Element) throws -> SegmentOfResult)
Returns an array containing the concatenated results of calling the
given transformation with each element of this sequence.
...
In fact, s.flatMap(transform) is equivalent to Array(s.map(transform).flatten()).
We may also take a look at the actual implementations of the two in the Swift source code (from which Swiftdoc is generated ...)
swift/stdlib/public/core/Join.swift
swift/stdlib/public/core/FlatMap.swift
Most noteably the latter source file, where the flatMap implementations where the used closure (transform) does not yield and optional value (as is the case here) are all described as
/// Returns the concatenated results of mapping `transform` over
/// `self`. Equivalent to
///
/// self.map(transform).joined()
From the above (assuming the compiler can be clever w.r.t. a simple over self { $0 } transform), it would seem as if performance-wise, the two alternatives should be equivalent, but joined does, imo, better show the intent of the operation.
In addition to intent in semantics, there is one apparent use case where joined is preferable over (and not entirely comparable to) flatMap: using joined with it's init(separator:) initializer to join sequences with a separator:
let array = [[1,2,3],[4,5,6],[7,8,9]]
let j = Array(array.joined(separator: [42]))
print(j) // [1, 2, 3, 42, 4, 5, 6, 42, 7, 8, 9]
The corresponding result using flatMap is not really as neat, as we explicitly need to remove the final additional separator after the flatMap operation (two different use cases, with or without trailing separator)
let f = Array(array.flatMap{ $0 + [42] }.dropLast())
print(f) // [1, 2, 3, 42, 4, 5, 6, 42, 7, 8, 9]
See also a somewhat outdated post of Erica Sadun dicussing flatMap vs. flatten() (note: joined() was named flatten() in Swift < 3).
Erica Sadun- Beta 6: flatten #swiftlang
I have a big array of objects and would like to split it into two arrays containing the objects in alternate order.
Example:
[0, 1, 2, 3, 4, 5, 6]
Becomes these two arrays (they should alternate)
[0, 2, 4, 6] and [1, 3, 5]
There are a ton of ways to split an array. But, what is the most efficient (least costly) if the array is huge.
There are various fancy ways to do it with filter but most would probably require two passes rather than one, so you may as well just use a for-loop.
Reserving space up-front could make a big difference in this case since if the source is large it’ll avoid unnecessary re-allocation as the new arrays grow, and the calculation of space needed is in constant time on arrays.
// could make this take a more generic random-access collection source
// if needed, or just make it an array extension instead
func splitAlternating<T>(source: [T]) -> ([T],[T]) {
var evens: [T] = [], odds: [T] = []
evens.reserveCapacity(source.count / 2 + 1)
odds.reserveCapacity(source.count / 2)
for idx in indices(source) {
if idx % 2 == 0 {
evens.append(source[idx])
}
else {
odds.append(source[idx])
}
}
return (evens,odds)
}
let a = [0,1,2,3,4,5,6]
splitAlternating(a) // ([0, 2, 4, 6], [1, 3, 5])
If performance is truly critical, you could use source.withUnsafeBufferPointer to access the source elements, to avoid the index bounds checking.
If the arrays are really huge, and you aren’t going to use the resulting data except to sample a small number of elements, you could consider using a lazy view instead (though the std lib lazy filter isn’t much use here as it returns sequence not a collection – you’d possibly need to write your own).
You can use the for in stride loop to fill two resulting arrays as follow:
extension Array {
var groupOfTwo:(firstArray:[T],secondArray:[T]) {
var firstArray:[T] = []
var secondArray:[T] = []
for index in stride(from: 0, to: count, by: 2) {
firstArray.append(self[index])
if index + 1 < count {
secondArray.append(self[index+1])
}
}
return (firstArray,secondArray)
}
}
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.firstArray // [0, 2, 4, 6]
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.secondArray // [1, 3, 5]
update: Xcode 7.1.1 • Swift 2.1
extension Array {
var groupOfTwo:(firstArray:[Element],secondArray:[Element]) {
var firstArray:[Element] = []
var secondArray:[Element] = []
for index in 0.stride(to: count, by: 2) {
firstArray.append(self[index])
if index + 1 < count {
secondArray.append(self[index+1])
}
}
return (firstArray,secondArray)
}
}
A more concise, functional approach would be to use reduce
let a = [0,1,2,3,4,5,6]
let (evens, odds) = a.enumerate().reduce(([Int](),[Int]())) { (cur, next) in
let even = next.index % 2 == 0
return (cur.0 + (even ? [next.element] : []),
cur.1 + (even ? [] : [next.element]))
}
evens // [0,2,4,6]
odds // [1,3,5]
Big/huge array always pose problems when being partially processed, like in this case, as creating two extra (even if half-sized) arrays can be both time and memory consuming. What if, for example, you just want to compute the mean and standard deviation of oddly and evenly positioned numbers, but this will require calling a dedicated function which requires a sequence as input?
Thus why not creating two sub-collections that instead of duplicating the array contents, they point to the original array, in a transparent manner to allow querying them for elements:
extension Collection where Index: Strideable{
func stride(from: Index, to: Index, by: Index.Stride) -> StridedToCollection<Self> {
return StridedToCollection(self, from: from, to: to, by: by)
}
}
struct StridedToCollection<C>: Collection where C: Collection, C.Index: Strideable {
private let _subscript : (C.Index) -> C.Element
private let step: C.Index.Stride
fileprivate init(_ collection: C, from: C.Index, to: C.Index, by: C.Index.Stride) {
startIndex = from
endIndex = Swift.max(to, startIndex)
step = by
_subscript = { collection[$0] }
}
let startIndex: C.Index
let endIndex: C.Index
func index(after i: C.Index) -> C.Index {
let next = i.advanced(by: step)
return next >= endIndex ? endIndex : next
}
subscript(_ index: C.Index) -> C.Element {
return _subscript(index)
}
}
The Collection extension and the associated struct would create a pseudo-array that you can use to access only the elements you are interested into.
Usage is simple:
let numbers: [Int] = [1, 2, 3, 4]
let stride1 = numbers.stride(from: 0, to: numbers.count, by: 2)
let stride2 = numbers.stride(from: 1, to: numbers.count, by: 2)
print(Array(stride1), Array(stride2))
With the above you can iterate the two strides without worrying you'll double the amount of memory. And if you actually need two sub-arrays, you just Array(stride)-ify them.
Use for loops. If the index value is even then send that to one array and if the index value is odd, then send that to odd array.
Here's, in my opinion, the easiest way
old_list = [0, 1, 2, 3, 4, 5, 6]
new_list1 =[]
new_list2 = []
while len(old_list)>0:
new_list1.append(old_list.pop(-1))
if len(old_list) != 0:
new_list2.append(old_list.pop(-1))
new_list1.reverse()
new_list2.reverse()
I just had to do this where I split an array into two in one place, and three into another. So I built this:
extension Array {
/// Splits the receiving array into multiple arrays
///
/// - Parameter subCollectionCount: The number of output arrays the receiver should be divided into
/// - Returns: An array containing `subCollectionCount` arrays. These arrays will be filled round robin style from the receiving array.
/// So if the receiver was `[0, 1, 2, 3, 4, 5, 6]` the output would be `[[0, 3, 6], [1, 4], [2, 5]]`. If the reviever is empty the output
/// Will still be `subCollectionCount` arrays, they just all will be empty. This way it's always safe to subscript into the output.
func split(subCollectionCount: Int) -> [[Element]] {
precondition(subCollectionCount > 1, "Can't split the array unless you ask for > 1")
var output: [[Element]] = []
(0..<subCollectionCount).forEach { (outputIndex) in
let indexesToKeep = stride(from: outputIndex, to: count, by: subCollectionCount)
let subCollection = enumerated().filter({ indexesToKeep.contains($0.offset)}).map({ $0.element })
output.append(subCollection)
}
precondition(output.count == subCollectionCount)
return output
}
}
It works on Swift 4.2 and 5.0 (as of 5.0 with Xcode 10.2 beta 2)