I have an 2d array like this:
let array= [ [0,2], [4,5], [4,1], [0,4] ]
and I'd like to get ONE element thats 0. index is the smallest in the array.
Result should be this:
let result = [0,2] // not also [0,4] because just the first one
This is what I've tried so far but obviously this is not a working solution :p
let result = array.filter { $0[1].map { return $0.min() } }
Thanks in advance, jonas
You can simply use Array.min then compare the first element of the nested arrays. min will return the first element in the original array that fits the minimum function in the closure in case there were several minima.
let array = [ [0,2], [4,5], [4,1], [0,4] ]
let result = array.min(by: {$0.first! < $1.first!}) //[0,2]
Related
I am trying to filter an array of array, based on another subarray. I am giving example below to make the requirement more clear. Please note that order of filterArray is important. I can iterate myArrayofArray using for loop, and then compare the element of each iterated element with filterArray. But I think Filter can be used in this case to get the resultArray. But a bit confused, how I'll implement it.
myArrayofArray = [[1,0,2], [1,2,0], [1,3,4], [1,2,1]]
filterArray = [1,0]
resultArray = [1,0,2]
The easiest way would be
let result = myArrayofArray.filter { $0.starts(with: filterArray) }
This will return a [[Int]] with zero or more matching arrays.
I would like to retrieve the first n elements of an array which could be nil and could also have less than n elements. Is there a "swifty" way to do it?
This works:
n=2
array = [1,2,3,4,5]
array.prefix(upTo: 2) // [1,2]
But I also want it to work with
array = [1] //I want to get [1]
or
array = nil //I want nil as return
Thanks!
You can use Optional.map and Sequence.prefix:
let n = 2
let array: [Int]? = [1,2,3,4,5]
let firstN = array.map { Array($0.prefix(n)) }
The result firstN is an optional array. It is nil if array
is nil, and an array with at most n elements of the given array
otherwise.
If an ArraySlice
result is good enough for your purpose then it can be
simplified to
let firstN = array?.prefix(n)
as #Duncan suggested.
Is there a way to grab the first non-zero element from an array of numbers?
I have an Array with many zeros at the beginning and I need only the first item that is not a zero.
For example:
let array = [0,0,0,0,25,53,21,77]
based on the above, the result should be 25.
What is the good way to achieve it?
You could get it like this:
let array = [0,0,0,0,25,53,21,77]
let firstNonZero = array.first { element -> Bool in
return element != 0
}
Or as a shorter version:
let firstNonZero = array.first(where: { $0 != 0 })
Note that firstNonZero would be an optional Int, so in case of array contains only zeros, firstNonZero would be nil.
Aside bar note: If you were wondering why to use first(where:) instead of filter(_:).first, you could check this question:
What is the difference between filter(_:).first and first(where:)?
I am currently having a big issue sorting my Data alphabetically in a 2D array. I'm going to try to give you every detail to be as clear as possible.
Currently, I am fetching my contacts with the CNContactStore. This all works fine. I am able to retrieve all the data I want out of my contacts.
Now, I created the following struct:
struct FavoritableContact {
let contact: CNContact
var hasFavorited: Bool
}
With this, I declared and initialized the following array:
var favoritableContacts = [FavoritableContact]()
Once I retrieved my contacts, I simply appended them to favoritableContacts;
try store.enumerateContacts(with: request, usingBlock: { (contact, stopPointerIfYouWantToStopEnumerating) in
favoritableContacts.append(FavoritableContact(contact: contact, hasFavorited: false))
})
To sort them in alphabetical order in the same array, I simply did the following:
var sortedContacts = favoritableContacts.sorted { $0.contact.familyName < $1.contact.familyName }
Now if possible, I want to create the following 2D array,
var 2D = [
[FavoritableContact] //"A"
[FavoritableContact], //"B"
[FavoritableContact], //"C"
[FavoritableContact], //"D"
...
]
I am just not sure how to take my sortedContacts array and separate alphabetically.
I am very new here, If I forgot something, or I didn't do somethign right please let me know.
As was pointed out in the comments, a dictionary with first letters as keys is probably the better way to go as it is much easier to access, though perhaps you have a reason for wanting to use a 2d array instead. To achieve that you could do something like this:
//Create an empty array filled with 26 arrays of FavorableContact
var array2d = Array<[FavoritableContact]>(repeating: [FavoritableContact](), count: 26)
//Find the ascii value for "A" to use as your base
let aAscii = Int("A".unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0]) //This returns 65, btw, so you could also just hardcode
//Go through your original array, find the first letter of each contact, and append to the correct array
favoritableContacts.forEach { (contact) in
//Get the ascii value for the first letter
let firstLetter = Int(contact.contact.familyName.prefix(1).uppercased().unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0])
//Append to the array for this letter by subtracting the ascii value for "A" from the ascii value for the uppercased version of this letter.
array2d[firstLetter - aAscii].append(contact)
}
This is not the cleanest thing in the world, and it assumes standard English language alphabet with no diacritics, symbols, numbers or anything else. Assuming that is true it gets the job done.
Could use something like this.
var contactsLeftToSort : [FavoritableContact] = []
var doubleArray : [[FavoritableContact]?] = [[FavoritableContact]?]()
var index : Int = 0
for char in "ABCDEFGHIJKLMNOPQRSTUV" {
doubleArray.append(nil)
var i = 0
while i < contactsLeftToSort.count {
let contact = contactsLeftToSort[i]
if contact.name.first == char {
doubleArray[index] == nil ? doubleArray[index] = [contact] : doubleArray[index]!.append(contact)
contactsLeftToSort.remove(at: i)
}
//assuming original list is alphabetized.. if not, delete this line.
if contact.name.first! > char { break }
i += 1
}
index += 1
}
As I wrote in the comments above, I think you can achieve this in a much more elegant way by using a dictionary instead of an array.
SWIFT 4
let sortedContacts: [FavoritableContact] = ... // An array of FavoritableContact objects, they should be sorted
let groupedContacts = Dictionary(grouping: contacts, by { $0.familyName.first! })
You now have a dictionary of all your contacts where the keys are the alphabetical letters (ie. A-Z) and the values are arrays of sorted FavoritableContact objects (assuming you sorted the big array of FavoritableContacts before creating the dictionary).
If you wanted to use this as the datasource for your tableview, you would make the number of sections all the possible first letters of family names. For the number of rows in each section, you return the count of the array for the key like so:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
let letterForSection = letterForSection() // Custom method to get the section of the letter
return contactsDict[letterForSection].count
}
The rest of the datasource methods would work in a similar way.
Man, all of these answers are really over-complicating this. All you need is something along the lines of:
let groupedContacts = Dictionary(grouping: contacts, by: { $0.contact.firstName.first! })
for initial, contacts in groupedContacts.lazy.sorted().{ $0.key < $1.key} {
print("#################", initial)
contacts.forEach{ print($0) }
}
I'm doing some operations like sorting, filter and grouped by some attributes of arrays object.
I'm adding objects of a filtered array in to another array like:
arrGroup.append(contentsOf: filteredArray)
My question is: will all of the objects maintain the same sorted order in the array every time, with 100% certainty?
Logically, will it add the object like
for object in filteredArray {
arrGroup.append(object)
}
or
for index in 0...filteredArray.count {
let object = filteredArray[index]
arrGroup.append(object)
}
For me, all are same, just difference in CPU cycle at run time. But my friend says that I should go with last option. Technically I'm getting same result for all three every time I debug my code.
Your suggestion please.
Yes, when you add an Array to another Array it will maintain the order as it is.
But yes if you are using Set then you might not get same order as it is not ordered collection but Array is ordered collection which maintains it's ordering until you changes it manually.
here is the code example :
var arr1 = ["1", "2" , "3"] // Print arr1 : ["1", "2", "3"]
let arr2 = ["4", "5" , "6"] // Print arr2 : ["4", "5", "6"]
arr1.append(contentsOf: arr2) // Print arr1 : ["1", "2", "3", "4", "5", "6"]
Array preserves whatever ordering you give it.
Array.append(contentsOf:) appends all items of the second array to the end of the first array, in order. Here's roughly what that algorithm would look like:
extension Array {
mutating func myAppend(contentsOf other: [Element]) {
reserveCapacity(self.count + other.count)
for element in other {
self.append(element)
}
}
}
Techniques for iterating an array
If you only need the elements
The preferred method
The preferred way to iterate the items of a Sequence is to use a typical for-in loop:
for element in array { // most preferred!
// use the element
}
The discouraged method
for i in 0 ..< array.count {
let element = array[i] // Avoid this!
// use the element
}
I highly advise against this technique. The reason is because it's very easy to fall victim to an off-by-one-error. In fact, your very own example has it!
for index in 0...filteredArray.count {
let object = filteredArray[index] // when index is filteredArray.count ... 💣
arrGroup.append(object)
}
Don't use this! Any array of n elements has indices 0 ..< n, not 0 ... n. Attempting to access array[array.count] will crash your program.
Another valid but discouraged method
for i in array.indices {
let element = array[i] // Avoid this!
// use the element
}
If you only need the indices
for i in array.indices {
// use the index i
}
If you need both the indices and the elements
for (i, element) in array.enumerated() {
// use the index i and the element.
}
The 2 for loops you have above are doing the same thing in terms of they will iterate from object #0 to the last object.
The first one is called fast enumeration and hence faster and more effective than the second.
And to answer your question. Yes the order will remain the same.