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:)?
Related
I dont know how doint that. I try find replacement obj method
indexOfObject on the swift but not find
i have array = [1,3,6,2,3] and input in array value 3, i am need find repeating value with min index from array. Answer with index 1. How do it?
You have to loop through the entire collection, for each item, see if we had seen this before. And as we are doing that, let’s keep track of the index of the first item that has been repeated somewhere in the collection, to see if this is the first repeated item or not:
extension Collection where Element: Hashable {
func indexOfFirstRepeated() -> Index? {
var result: Index? // the index of the first item repeated anywhere else in the collection
var firstOccurrences: [Element: Index] = [:] // dictionary to keep track of the first item that every element was first encountered in the collection
for (index, element) in zip(indices, self) {
if let firstOccurrence = firstOccurrences[element] { // find previous occurrence of this value, if any
if let previousLowestIndex = result { // if we found this element before, let's see if we had already found another repeated element
if firstOccurrence < previousLowestIndex { // if so, let’s see if the first occurrence of this element occurred before the first occurrence of the previously discovered repeated element
result = firstOccurrence
}
} else { // otherwise, no prior repeated element found, so this is our first repeated element found thus far
result = firstOccurrence
}
} else {
firstOccurrences[element] = index // if we got here, this is the first time we've seen this element, so record the index of this first occurrence
}
}
return result
}
}
Thus:
let array = [9,8,7,1,3,6,2,3,1]
if let index = array.indexOfFirstRepeated() {
print(index) // 3
}
Now, obviously, as we iterate through this array, the value 3 is the first value that we will see repeated, but that doesn’t matter, because the repeated value 1 will be found at the very end of the array, and 1’s first index is lower than 3’s first index.
Two observations on the above:
I made it generic, so that it works on any hashable type, e.g.:
let array = ["bill", "sam", "susan", "sam", "bill"]
if let index = array.indexOfFirstRepeated() {
print(index)
} else {
print("not found")
}
I made this a Collection extension (rather than an Array extension) so that it would work on other collection types (e.g. array slices, etc.). You can make it an Array extension, just as easily, but we prefer to use the most abstract type that is convenient, to make it as flexible as possible.
This is basically a riff on uniqued.
import Algorithms
public extension BidirectionalCollection where Element: Hashable {
var firstDuplicate: (index: Index, element: Element)? {
var set: Set<Element> = []
return indexed().reversed().reduce(into: nil) {
if !set.insert($1.element).inserted {
$0 = $1
}
}
}
}
You can get the last duplicate by not reversing before reducing.
Assume you have an array of n integers, with a[i] = i, except that a[1] = a[2] = 1, and I may or may not have have changed a[i] = 0 for some i >= 2.
The smallest index of a duplicate element is either 0 or 1. To find out which you have to find the i >= 2 with a[i] = 0 or find that no such i exists. So you have to visit all array elements.
This question already has answers here:
Sorting array alphabetically with number
(8 answers)
Closed 4 years ago.
I'm trying to sort an array by comparing a string value from two items, the values of the property are a number but of type String. How can I convert them to Int and check which is greater. Current code looks like this.
libraryAlbumTracks = tracks.sorted {
$0.position!.compare($1.position!) == .orderedAscending
}
but values like "13" come before "2" because it's a string. I tried to cast the values to Int but because they are optional, I get the error that operand ">" cannot be applied to type Int?
Please how can I go around this in the sorted function?
Provide the numeric option when using compare. This will properly sort strings containing numbers and it also works if some of the string don't actually have numbers or the strings have a combination of numbers and non-numbers.
libraryAlbumTracks = tracks.sorted {
$0.position!.compare($1.position!, options: [ .numeric ]) == .orderedAscending
}
This avoids the need to convert the strings to Int.
Note: You should also avoid force-unwrapping position. Either don't make them optional if it's safe to force-unwrap them, or safely unwrap then or use ?? to provide an appropriate default when comparing them.
libraryAlbumTracks = tracks.sorted {
guard let leftPosition = $0.position,
let leftInt = Int(leftPosition),
let rightPosition = $1.position,
let rightInt = Int(rightPosition) else {
return false
}
return leftInt > rightInt
}
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]
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) }
}
How can I show array count minus array count? I have two arrays like this:
var likedBy = [NSArray]()
var dislikedBy = [NSArray]()
And I am trying to get the count as a string on UITextLabel like this:
imageCell.likeLabel.text = self.likedBy.count - self.dislikedBy.count
But I get error:
No "-" candidates produce the expected contextual result type
"String?"
Any suggestions?
You should use string interpolation with \() because count property returns Int and you need a String to set the text property:
imageCell.likeLabel.text = "\(self.likedBy.count - self.dislikedBy.count)"
replace your line
imageCell.likeLabel.text = "\(self.likedBy.count - self.dislikedBy.count)"
You might also want to write an extension on NSArray to provide a element count difference so your code is cleaner and the responsibilities lie in the right place. As in, your main code flow is not interested in working out the difference between two array counts, it wants to know how many likes there are left, after the dislikes have been subtracted.
extension NSArray {
func elementCountDiff(array: NSArray) -> Int {
return self.count - array.count
}
}
...
imageCell.likeLabel.text = String(self.likedBy.elementCountDiff(self.dislikedBy))