Remove the first par of bracket from an Array Swift 3 - arrays

I have this array with double pairs of bracket [["0": 5, "2": 10]] and I want to convert it to ["5","10"] or [5,10]

let dict = [["0": 5, "2": 10]]
let dict0 = dict[0]
var array: [Int] = []
array.append(dict0["0"]!)
array.append(dict0["2"]!)

This will do the trick. We're just extracting the dictionary values and creating an array. If you had a long list you could put your dictionary through a for-loop.
let dictionary = [["0": 5, "2": 10]]
let array = [dictionary[0]["0"]!,dictionary[0]["2"]!]
print("array: \(array)")

I don't know what you are trying to achieve here. But this solution does exactly what you asked in your question. i.e. convert an Array of Array of Dictionary into an Array ( [["0": 5, "2": 10]] -> [5,10] )
let data = [["0": 5, "2": 10]]
var finalArray = Array<Any>()
for dictArr in data {
for (key,value) in dictArr {
finalArray.append(value) //[5,10]
}
}
If you want to convert an Array of Array of Dictionary into an Array of Array of Element ( [["0": 5, "2": 10]] -> [[5,10]] ), use the following code.
let data = [["0": 5, "2": 10]]
var finalArray = Array<Any>()
for dictArr in data {
var tempArr = [Int]()
for (key,value) in dictArr {
tempArr.append(value)
}
finalArray.append(tempArr) //[[5,10]]
}

Related

Compare an array with another & then return the index of matched results

Sorry if this is a dumb question but everything I try seems to be wrong! (I am new to Swift).
I have 2 arrays of Strings which I need to compare for matches and then return an array with the index position of those matches .... IE:
let array1 = ["abc", "def", "ghi", "jkl", "xyz", "uhr"]
let array2 = ["ghi", "xyz", "uhr"]
// Search array1 for instances of array2
// Result I want is: [2, 4, 5]
Is there a simple function I am missing?! Thanks in advance for your help.
For an efficient solution you can create an index first. The index maps each element in the first array to its position in the array. Both arrays are traversed only once:
let array1 = ["abc", "def", "ghi", "jkl", "xyz", "uhr"]
let array2 = ["ghi", "xyz", "uhr"]
let index = Dictionary(uniqueKeysWithValues: array1.enumerated().map {
($0.element, $0.offset)
})
let result = array2.compactMap { index[$0] }
print(result) // [2, 4, 5]
If the elements in array1 are not known to be unique then the index must be computed slightly differently:
let index = Dictionary(array1.enumerated().map { ($0.element, $0.offset) },
uniquingKeysWith: { (first, _) in first })
The second parameter is a closure which controls which value to put into the dictionary in the case of duplicate keys. Here we choose the position of the first occurrence of an element in the array.
var indexArr: [Int] = []
for element in array2 {
if let elementIndex = array1.firstIndex(of: element) {
indexArr.append(elementIndex)
}
}
print(indexArr)
var results: [Int] = []
for i in 0..<array1.count {
for j in 0..<array2.count {
if array1[i] == array2[j] {
results.append(i)
}
}
}
print(results)

Reverse array by group size

I was trying to solve this challenge: reverse an array of elements by groups given a group size.
Given Array: [1, 2, 3, 4, 5, 6]
Desired Result (group size of 3): [4, 5, 6, 1, 2, 3]
If last group has less elements than the group size, then just add them and finish, as follows:
Given Array: [1, 2, 3, 4, 5, 6, 7]
Desired Result: [5, 6, 7, 2, 3, 4, 1]
I tried this and it is working, but it looks kinda weird for me. Can anyone help me find a cleaner or much more intuitive solution?
extension Array {
func reverse(groupSize: Int) -> [Element] {
var reversed = [Element]()
let groups = count / groupSize
for group in 0...groups {
let lowerBound = count - group * groupSize - groupSize
let upperBound = count - 1 - group * groupSize
if lowerBound >= 0 {
reversed += Array(self[lowerBound...upperBound])
} else {
reversed += Array(self[0...upperBound])
}
}
return reversed
}
}
The following solution is based on a combo of stride+map:
let groupSize = 3
let array = [1, 2, 3, 4, 5, 6]
let reversedArray = Array(array.reversed())
let result = stride(from: 0, to: reversedArray.count, by: groupSize).map {
reversedArray[$0 ..< min($0 + groupSize, reversedArray.count)].reversed()
}.reduce([Int](), +)
print(result) // [4, 5, 6, 1, 2, 3]
You could say:
extension Array {
func groupedReversing(stride: Int) -> [Element] {
precondition(stride > 0, "stride must be > 0")
return Swift.stride(from: count, to: 0, by: -stride)
.flatMap { self[Swift.max(0, $0 - stride) ..< $0] }
}
}
let result = Array(1 ... 7).groupedReversing(stride: 3)
print(result) // [5, 6, 7, 2, 3, 4, 1]
We're using stride(from:through:by:) to iterate from array.count (inclusive) to 0 (exclusive) in increments of (minus) the stride. The Swift. prefix is in order to disambiguate it from the obsoleted Swift 2 stride method (which will be gone in Swift 4.1).
Then, we're flat-mapping the index to a slice of the input array that's up to stride elements long (truncating at the beginning of the array as we clamp the lower index to 0). And because this is flatMap, the resulting slices are concatenated into a single resulting array.
You could also implement a fully generic version across Sequence by first providing an implementation on BidirectionalCollection, advancing indices backwards and appending slices into a resulting array:
extension BidirectionalCollection {
func groupedReversing(stride: Int) -> [Element] {
precondition(stride > 0, "stride must be > 0")
var result: [Element] = []
result.reserveCapacity(numericCast(count))
var upper = endIndex
while upper != startIndex {
// get the next lower bound for the slice, stopping at the start index.
let lower = index(upper, offsetBy: -numericCast(stride),
limitedBy: startIndex) ?? startIndex
result += self[lower ..< upper]
upper = lower
}
return result
}
}
and then implement an overload on Sequence that first converts to an array, and then forwards onto the above implementation:
extension Sequence {
func groupedReversing(stride: Int) -> [Element] {
return Array(self).groupedReversing(stride: stride)
}
}
Now you can call it on, for example, a CountableClosedRange without first having to convert it to an array:
let result = (1 ... 7).groupedReversing(stride: 3)
print(result) // [5, 6, 7, 2, 3, 4, 1]
I think your function is okay, not sure what you meant by weird tbh, can separate to chunk or add each elements in reversed way ,but logic is same anyway, just need to mind the performance/complexity of each ways:
let a = [1,2,3,4,5,6,7,8,9,10,11]
extension Array {
func reverse(group: Int) -> [Element] {
guard group > 1 else { return self.reversed() }
var new = [Element]()
for i in stride(from: self.count-1, through: 0, by: -group) {
let k = i-group+1 < 0 ? 0 : i-group+1
for j in k...i {
new.append(self[j])
}
}
return new
}
}
a.reverse(group: 4) //[8, 9, 10, 11, 4, 5, 6, 7, 1, 2, 3]
The two following Swift 5 code snippets show how to implement a Collection or Array extension method in order to chunked it, reverse it then flatten it into a new array.
#1. Using AnyIterator and Sequence joined()
extension Collection {
func reverseFlattenChunked(by distance: Int) -> [Element] {
precondition(distance > 0, "distance must be greater than 0")
var index = endIndex
let iterator = AnyIterator({ () -> SubSequence? in
let newIndex = self.index(index, offsetBy: -distance, limitedBy: self.startIndex) ?? self.startIndex
defer { index = newIndex }
return index != self.startIndex ? self[newIndex ..< index] : nil
})
return Array(iterator.joined())
}
}
Usage:
let array = ["1", "2", "3", "4", "5", "6", "7"]
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: ["5", "6", "7", "2", "3", "4", "1"]
let array: [String] = ["1", "2", "3", "4", "5", "6"]
let newArray = array.reverseFlattenChunked(by: 2)
print(newArray) // prints: ["5", "6", "3", "4", "1", "2"]
let array: [String] = []
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: []
#2. Using stride(from:to:by:) and Sequence flatMap(_:)
extension Array {
func reverseFlattenChunked(by distance: Int) -> [Element] {
precondition(distance > 0, "distance must be greater than 0")
let indicesSequence = stride(from: self.endIndex, to: self.startIndex, by: -distance)
let array = indicesSequence.flatMap({ (index) -> SubSequence in
let advancedIndex = self.index(index, offsetBy: -distance, limitedBy: self.startIndex) ?? self.startIndex
// let advancedIndex = index.advanced(by: -distance) <= self.startIndex ? self.startIndex : index.advanced(by: -distance) // also works
return self[advancedIndex ..< index]
})
return array
}
}
Usage:
let array = ["1", "2", "3", "4", "5", "6", "7"]
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: ["5", "6", "7", "2", "3", "4", "1"]
let array: [String] = ["1", "2", "3", "4", "5", "6"]
let newArray = array.reverseFlattenChunked(by: 2)
print(newArray) // prints: ["5", "6", "3", "4", "1", "2"]
let array: [String] = []
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: []

Nested arrays using Any/AnyObject

According to Apple's official book "The Swift Programming Language (Swift 2.1)":
AnyObject can represent an instance of any class type.
Any can represent an instance of any type at all, including function types.
Knowing that, I wanted to emulate Python-like nested list using an Any array.
let array = [1, 2, [3, 4], [5, 6, [7, 8]], 1]
Since Int and Array are value types, I supposed that array would be typed as [Any]
But this wasn't the case here :
func flatten(list:[Any]) -> [Any] {
var new = [Any]()
for element in list {
if let array = element as? [Any] {
// this code never runs
let flattened = flatten(array)
for x in flattened {
new.append(y)
}
}else{
new.append(element)
}
}
return new
}
Note: calling this function gave me EXC_BAD_INSTRUCTION error at first until I did this tweak :
let array : [Any] = [1, 2, [3, 4], [5, 6, [7, 8]], 1]
Output : [1, 2, [3, 4], [5, 6, [7, 8]], 1]
Expected : [1, 2, 3, 4, 5, 6, 7, 8, 1]
Unexplained Solution:
I replaced everywhere in this example Any by AnyObject
Numbers now are of type NSNumber
func flatten(list:[AnyObject]) -> [AnyObject] {
var new = [AnyObject]()
for element in list {
if let array = element as? [AnyObject] {
let flattened = flatten(array)
for x in flattened {
new.append(y)
}
}else{
new.append(element)
}
}
return new
}
Output : [1, 2, 3, 4, 5, 6, 7, 8, 1]
Expected : [1, 2, 3, 4, 5, 6, 7, 8, 1]
Question :
Why is it working with [AnyObject] / NSArray and not with [Any], despite the fact that integer literals are mainly of type Int not NSNumber and array literals are of type Array and not NSArray? Is something wrong with my example?
When you use Any, Swift will wrap your nested array elements into NSArray and not into Swift arrays (which can't hold all Objective-C types). So your test if let array = element as? [Any] { will not be true if you use Any because the resulting array isn't of type [Any] but NSArray.
So if you want a function that manages Any you can change your test for:
if let nestedArray = element as? NSArray {
You then have to define a new flattenArray() function with an NSArray prototype:
func flattenArray(array: NSArray) -> [Any] {
var flattenedArray: [Any] = []
for element in array {
// We have an array
if let nestedArray = element as? NSArray {
flattenedArray = flattenedArray + flattenArray(nestedArray)
} else {
// We have a single element
flattenedArray.append(element)
}
}
return flattenedArray
}
func flattenArray(array: [Any]) -> [Any] {
var flattenedArray: [Any] = []
for element in array {
// We have an array
if let nestedArray = element as? NSArray {
flattenedArray = flattenedArray + flattenArray(nestedArray)
} else {
// We have a single element
flattenedArray.append(element)
}
}
return flattenedArray
}
and it will do the trick.
We could probably imagine a more elegant solution but with this example you get the idea behind this issue.

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