Turn 1d array into 2d array in swift [duplicate] - arrays

This question already has answers here:
How can split from string to array by chunks of given size
(9 answers)
Closed 3 years ago.
If I have a one-dimensional array:
oneDimArray = [1,2,3,4,5,6,7,8,9]
and I already have a 3X3 two-dimensional array with the right amount of slots to fit the numbers
twoDimArray = [[0,0,0], [0,0,0], [0,0,0]]
...how do I fit the oneDimArray numbers into the twoDimArray, like:
[[1,2,3], [4,5,6], [7,8,9]]
?
I know I can do this with a couple of nested for-loops, but is there a simpler, functional way to do this?

Here is one way to do it. Make an iterator out of your one dimensional array, and then use map and compactMap along with .next() to replace the values of the twoDimArray to create the newArray:
let oneDimArray = [1,2,3,4,5,6,7,8,9]
let twoDimArray = [[0,0,0], [0,0,0], [0,0,0]]
var iter = oneDimArray.makeIterator()
let newArray = twoDimArray.map { $0.compactMap { _ in iter.next() } }
print(newArray)
Output
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
A nice feature of this technique is that you can easily fill in any pattern of array, and not just create a fixed 3x3 one for instance:
let oneDimArray = [1,2,3,4,5,6,7,8,9,10]
let patternArray = [[0], [0,0], [0,0,0], [0,0,0,0]]
var iter = oneDimArray.makeIterator()
let newArray = patternArray.map { $0.compactMap { _ in iter.next() } }
print(newArray)
Output
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
A generic function
We can turn this into a generic function that can replace the values of a 2D array with those of a 1D array. Note that the types of the values in the arrays can be different if you like:
func overlay<T, U>(_ array: [[T]], values: [U]) -> [[U]] {
var iter = values.makeIterator()
return array.map { $0.compactMap { _ in iter.next() }}
}
// Create an 2D array of strings from this pattern
let patternArray = [[0], [0,0], [0,0,0], [0,0,0,0]]
print(overlay(patternArray, values: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]))
Output
[["a"], ["b", "c"], ["d", "e", "f"], ["g", "h", "i", "j"]]

You can loop over index and value using enumerated and then calculate the correct postion using % and /
for (index, num) in oneDimArray.enumerated() {
twoDimArray[index / 3][index % 3] = num
}

var index = 0
twoDimArray.indices.forEach { (outerInd) in
twoDimArray[outerInd].indices.forEach { (innerInd) in
twoDimArray[outerInd][innerInd] = oneDimArray[index]
index += 1
}
}

for i in twoDimArray.indices {
for j in twoDimArray[i].indices {
twoDimArray[i][j] = oneDimArray.removeFirst();
}
}

Related

Multidimensional array - get value of each element at same time

Having issue creating the logic for this. Is it even possible ?
Let’s say you have
Var one = [[1,1,1]]
Var two = [[2,2,2]]
Var three = [[3,3,3]]
Var k = [one,two,three]
Assume you won’t know the length of var “k”.
I’m trying to write a function that will allow me to access all elements in “k” at the same time and access each index value.
Example.
k[0][0]
k[1][0]
k[2][0]
——————
k[0][1]
k[1][1]
k[2][1]
——————
I know for loops is a start but I’m stuck when it comes to accessing each element at the same time Dynamically. Is this even possible ?
Not sure what you are trying to achieve.
If you want to build a 3 x 3 matrix you can write
var one = [1,1,1]
var two = [2,2,2]
var three = [3,3,3]
var k = [one, two, three]
Now you have in memory the equivalent of this matrix
1, 1, 1
2, 2, 2
3, 3, 3
And you can access an element using this syntax
k[i][j]
where i and j are integers between 0 and 2.
Example
k[0][0] // 1
If you are looking for a good way to work with a matrix have a look here https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html#subscripts
Rather than working directly against the 2D array I wrapped it in a struct Matrix where the function column(at:) will return all values in a column. The struct is generic to allow for different element types
struct Matrix<T> {
private var data: [[T]]
private init() {
data = []
}
init(rows: [T]...) {
self.init()
let check = rows.first?.count ?? 0
for row in rows {
guard row.count == check else { fatalError("All rows must be the same length")}
data.append(row)
}
}
func row(at index: Int) -> [T]? {
guard index < data.count else { return nil }
return data[index]
}
func column(at index: Int) -> [T]? {
guard !data.isEmpty else { return nil }
var column = [T]()
for i in 0..<data.count {
column.append(data[i][index])
}
return column
}
}
And it can be used like this
let matrix = Matrix(rows: [1,1,2],[2,2,2],[3,3,3])
print(matrix.column(at: 1))
print(matrix.row(at: 1))
let matrix2 = Matrix(rows: ["a", "b"], ["c", "d"], ["e", "f"],["g", "h"])
print(matrix2.column(at: 1))
print(matrix2.row(at: 1))
[1, 2, 3]
[2, 2, 2]
["b", "d", "f", "h"]
["c", "d"]

2D array Swift goes out of bounds when appending arrays [duplicate]

This question already has answers here:
Why is this array out of index?
(2 answers)
Closed 4 years ago.
I want to append elements from one 2D array to the another 2D array, but I get fatal error index out of bound.
the code is as follows:
var array = [["a", "b", "c"], ["d","e","f"],["g","h","i"]]
var array2 = [[String]]()
var x = array.count
var y = array[1].count
for j in 0..<x {
for i in 0..<y {
array2[j].append(array[j][i])
}
}
print(array2)
please don't tell me to just copy the array as this is not what I need, I am using this procedure to do something more complex than just copying an array.
Any suggestions as to why it goes out of bounds?
thanks
array2[j] doesn't exist as it's just an empty array.
It would be much easier to do this:
var array = [["a", "b", "c"], ["d","e","f"],["g","h","i"]]
var array2 = [[String]]()
for item in array {
array2.append(item)
}
print(array2)
[["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
But that is just copying the array exactly. You should provide a more precise example of what you are trying to achieve.
Another option (Which makes your current code work) is to create a 'row' in the first loop ready for insertion:
var array = [["a", "b", "c"], ["d","e","f"],["g","h","i"]]
var array2 = [[String]]()
var x = array.count
var y = array[1].count
for j in 0..<x {
array2.append([String]())
for i in 0..<y {
array2[j].append(array[j][i])
}
}
print(array2)
Which gives the same output:
[["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
It is going out of bounds because array2[0] doesn't exist. You need to create an an empty array there before appending to it. Then append that array to the outer array.
var array = [["a", "b", "c"], ["d","e","f"],["g","h","i"]]
var array2 = [[String]]()
for j in 0..<array.count {
var stringArray: [String] = []
for i in 0..<array[j].count {
stringArray.append(array[j][i])
}
array2.append(stringArray)
}
print(array2)

Swift 3 Remove objects from an array that are present in another array using set and maintaining order [duplicate]

This question already has answers here:
iOS swift remove elements of an array from another array
(9 answers)
Closed 5 years ago.
Array1 = [1, 2, 3, 4, 5, 6]
Array2 = [1,5]
I want to get:
Array1 = [2, 3, 4, 6]
I want to do this by using Set because these arrays may get larger.
Also it is important that I maintain the order of the array.
Create a set with all elements from the second array,
then filter the first array to get only the elements which are not
in the set:
let array1 = [5, 4, 1, 2, 3, 4, 1, 2]
let array2 = [1, 5]
let set2 = Set(array2)
let result = array1.filter { !set2.contains($0) }
print(result) // [4, 2, 3, 4, 2]
This preserves the order (and duplicate elements) from the first
array. Using a set is advantageous if the second array can be large,
because the lookup is faster.
var array1 = [1, 2, 3, 4, 5, 6]
var array2 = [1,5]
var arrayResult = array1.enumerated()
.filter { !array2.contains($0.0 + 1) }
.map { $0.1 }
print(arrayResult)
[2, 3, 4, 6]
Another ways to achieve the same result:
1. User filter
let arrayResult = array1.filter { element in
return !array2.contains(element)
}
2. Use Sort
array2.sorted(by: >).forEach { if $0 < self.array1.count { self.array1.remove(at: $0) } }
Remove elements using indexes array:
Array of Strings and indexes
let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
let indexAnimals = [0, 3, 4]
let arrayRemainingAnimals = animals
.enumerated()
.filter { !indexAnimals.contains($0.offset) }
.map { $0.element }
print(arrayRemainingAnimals)
//result - ["dogs", "chimps", "cow"]
Array of Integers and indexes
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let indexesToRemove = [3, 5, 8, 12]
numbers = numbers
.enumerated()
.filter { !indexesToRemove.contains($0.offset) }
.map { $0.element }
print(numbers)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Remove elements using element value of another array
Arrays of integers
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Arrays of strings
let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
let arrayRemoveLetters = ["a", "e", "g", "h"]
let arrayRemainingLetters = arrayLetters.filter {
!arrayRemoveLetters.contains($0)
}
print(arrayRemainingLetters)
//result - ["b", "c", "d", "f", "i"]
Use the filter function
let result = Array1.filter { element in
return !Array2.contains(element)
}
(Note: because you added to your question and maintaining order then my answer is not right anymore, because Set don't preserve the order. then the filter answers are a better fit)
use subtracting from a Set:
array1 = Array(Set(array1).subtracting(Set(array2)))
you can add this as an operator :
Using the Array → Set → Array method mentioned by Antonio, and with the convenience of an operator, as freytag pointed out, I've been very satisfied using this:
// Swift 3.x
func - <Element: Hashable>(lhs: [Element], rhs: [Element]) -> [Element]
{
return Array(Set<Element>(lhs).subtracting(Set<Element>(rhs)))
}
quoted from: https://stackoverflow.com/a/42679608/1930509
let array1 = [1, 2, 3, 4, 5, 6]
let array2 = [1,5]
let array3 = array1.reduce([]) { array2.contains($1) ? $0 : $0 + [$1] }
print(array3) // "[2, 3, 4, 6]\n"

How to split an array in half in Swift?

How do I split a deck of cards? I have an array made and a random card dealer, but have no idea how to split the deck.
Thanks everyone for the help! I now have a working card app, did run into other problems but they were solved quickly.
You can make an extension so it can return an array of two arrays, working with Ints, Strings, etc:
extension Array {
func split() -> [[Element]] {
let ct = self.count
let half = ct / 2
let leftSplit = self[0 ..< half]
let rightSplit = self[half ..< ct]
return [Array(leftSplit), Array(rightSplit)]
}
}
let deck = ["J", "Q", "K", "A"]
let nums = [0, 1, 2, 3, 4]
deck.split() // [["J", "Q"], ["K", "A"]]
nums.split() // [[0, 1], [2, 3, 4]]
But returning a named tuple is even better, because it enforces the fact that you expect exactly two arrays as a result:
extension Array {
func split() -> (left: [Element], right: [Element]) {
let ct = self.count
let half = ct / 2
let leftSplit = self[0 ..< half]
let rightSplit = self[half ..< ct]
return (left: Array(leftSplit), right: Array(rightSplit))
}
}
let deck = ["J", "Q", "K", "A"]
let splitDeck = deck.split()
print(splitDeck.left) // ["J", "Q"]
print(splitDeck.right) // ["K", "A"]
Note: credits goes to Andrei and Qbyte for giving the first correct answer, I'm just adding info.
You can use subscript range
let deck: [String] = ["J", "Q", "K", "A"]
// use ArraySlice only for transient computation
let leftSplit: ArraySlice<String> = deck[0 ..< deck.count / 2] // "J", "Q"
let rightSplit: ArraySlice<String> = deck[deck.count / 2 ..< deck.count] // "K", "A"
// make arrays from ArraySlice
let leftDeck: [String] = Array(leftSplit) // "J", "Q"
let rightDeck: [String] = Array(rightSplit) // "K", "A"
EDIT: above code is for Swift 2, maybe for Swift 3 is a more convenient way.
Swift
More generic solution to split the array into chunks the answer from this link
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
let numbers = Array(1...100)
let result = numbers.chunked(into: 5)
And one more realization of previously provided ideas. Firstly, up to Swift current documentation, it is better to choose names in past simple tense for functions that produce some result and present tense for mutating ones.
As second, as for me, it is better to choose half adding count % 2 to give more uniformed result.
Here is it:
extension Array {
func devided() -> ([Element], [Element]) {
let half = count / 2 + count % 2
let head = self[0..<half]
let tail = self[half..<count]
return (Array(head), Array(tail))
}
}
And results:
let set1 = [1, 2, 3, 4, 5, 6, 7,8]
let set2 = [1, 2, 3, 4, 5]
let set3 = [1]
let set4 = [Int]()
print(set1.devided())
print(set2.devided())
print(set3.devided())
print(set4.devided())
([1, 2, 3, 4], [5, 6, 7, 8])
([1, 2, 3], [4, 5])
([1], [])
([], [])
You can create an extension on SequenceType, and create a function named divide.
This function would iterate through the elements of the sequence while placing those that match the predicate into one array (slice) and those that do not match into another array (remainder).
The function returns a tuple containing the slice and the remainder.
extension SequenceType {
/**
Returns a tuple with 2 arrays.
The first array (the slice) contains the elements of self that match the predicate.
The second array (the remainder) contains the elements of self that do not match the predicate.
*/
func divide(#noescape predicate: (Self.Generator.Element) -> Bool) -> (slice: [Self.Generator.Element], remainder: [Self.Generator.Element]) {
var slice: [Self.Generator.Element] = []
var remainder: [Self.Generator.Element] = []
forEach {
switch predicate($0) {
case true : slice.append($0)
case false : remainder.append($0)
}
}
return (slice, remainder)
}
}
This is an example
let tuple = [1, 2, 3, 4, 5].divide({ $0 >= 3 })
tuple.slice // [3, 4, 5]
tuple.remainder // [1, 2]

Removing objects from an array based on another array

I have two arrays like this:
var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]
As you can see, James and Steve match and I want to be able to remove them from arrayA. How would I write this?
#francesco-vadicamo's answer in Swift 2/3/4+
arrayA = arrayA.filter { !arrayB.contains($0) }
The easiest way is by using the new Set container (added in Swift 1.2 / Xcode 6.3):
var setA = Set(arrayA)
var setB = Set(arrayB)
// Return a set with all values contained in both A and B
let intersection = setA.intersect(setB)
// Return a set with all values in A which are not contained in B
let diff = setA.subtract(setB)
If you want to reassign the resulting set to arrayA, simply create a new instance using the copy constructor and assign it to arrayA:
arrayA = Array(intersection)
The downside is that you have to create 2 new data sets.
Note that intersect doesn't mutate the instance it is invoked in, it just returns a new set.
There are similar methods to add, subtract, etc., you can take a look at them
Like this:
var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]
for word in arrayB {
if let ix = find(arrayA, word) {
arrayA.removeAtIndex(ix)
}
}
// now arrayA is ["Mike", "Stacey"]
I agree with Antonio's answer, however for small array subtractions you can also use a filter closure like this:
let res = arrayA.filter { !contains(arrayB, $0) }
matt and freytag's solutions are the ONLY ones that account for duplicates and should be receiving more +1s than the other answers.
Here is an updated version of matt's answer for Swift 3.0:
var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]
for word in arrayB {
if let ix = arrayA.index(of: word) {
arrayA.remove(at: ix)
}
}
Original answer
This can also be implemented as a minus func:
func -<T:RangeReplaceableCollectionType where T.Generator.Element:Equatable>( lhs:T, rhs:T ) -> T {
var lhs = lhs
for element in rhs {
if let index = lhs.indexOf(element) { lhs.removeAtIndex(index) }
}
return lhs
}
Now you can use
arrayA - arrayB
Updated implementation for Swift 5
func -<T: RangeReplaceableCollection>(lhs: T, rhs: T) -> T where T.Iterator.Element: Equatable {
var lhs = lhs
for element in rhs {
if let index = lhs.firstIndex(of: element) { lhs.remove(at: index) }
}
return lhs
}
Using the Array → Set → Array method mentioned by Antonio, and with the convenience of an operator, as freytag pointed out, I've been very satisfied using this:
// Swift 3.x/4.x
func - <Element: Hashable>(lhs: [Element], rhs: [Element]) -> [Element]
{
return Array(Set<Element>(lhs).subtracting(Set<Element>(rhs)))
}
For smaller arrays I use:
/* poormans sub for Arrays */
extension Array where Element: Equatable {
static func -=(lhs: inout Array, rhs: Array) {
rhs.forEach {
if let indexOfhit = lhs.firstIndex(of: $0) {
lhs.remove(at: indexOfhit)
}
}
}
static func -(lhs: Array, rhs: Array) -> Array {
return lhs.filter { return !rhs.contains($0) }
}
}
Remove elements using indexes array:
Array of Strings and indexes
let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
let indexAnimals = [0, 3, 4]
let arrayRemainingAnimals = animals
.enumerated()
.filter { !indexAnimals.contains($0.offset) }
.map { $0.element }
print(arrayRemainingAnimals)
//result - ["dogs", "chimps", "cow"]
Array of Integers and indexes
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let indexesToRemove = [3, 5, 8, 12]
numbers = numbers
.enumerated()
.filter { !indexesToRemove.contains($0.offset) }
.map { $0.element }
print(numbers)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Remove elements using element value of another array
Arrays of integers
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Arrays of strings
let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
let arrayRemoveLetters = ["a", "e", "g", "h"]
let arrayRemainingLetters = arrayLetters.filter {
!arrayRemoveLetters.contains($0)
}
print(arrayRemainingLetters)
//result - ["b", "c", "d", "f", "i"]

Resources