This question already has answers here:
Unique values of array in swift [duplicate]
(4 answers)
Removing duplicate elements from an array in Swift
(49 answers)
Closed 4 years ago.
I have an array which has repeated items, i want to get unique items only so i did this:
let decoded = userDefaults.object(forKey: "shifts") as! Data
myShifts = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! [Shift]
filtered_shifts = myShifts.filter{$0.regionName == region && $0.cityName == city && $0.idService == idservice && $0.quantityStaff != 0}
for shift in filtered_shifts {
let decoded4 = userDefaults.object(forKey: "nationalities") as! Data
let decodedNationalities = NSKeyedUnarchiver.unarchiveObject(with: decoded4) as! [Nationality]
for nationality in decodedNationalities {
if nationality.id == shift.idNationality{
nationalitiesid.append(nationality.id)
nationalities.append(nationality.name)
}
}
}
uniqueNationality = Array(Set(nationalities))
uniqueNationalityid = Array(Set(nationalitiesid))
which is getting me a new array with unique items as i need...
the problem is that the order is diferent when i want the same order ... for exampple:
nationalitiesid = [3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4]
nationalities = ["Indian", "Indian", "Indian", "Indian", "Indian", "Indian", "Indian", "Indian", "Philippines", "Philippines", "Philippines", "Philippines"]
the unique array is:
uniqueNationality = ["Indian", "Philippines"]
uniqueNationalityid = [4, 3]
and this is wrong since Indian id is 3 and Philippines id is 4!
it should be:
uniqueNationalityid = [3, 4]
How to solve this?
let uniqueList = nationalities.reduce([], {
$0.contains($1) ? $0 : $0 + [$1]
})
This does not directly answer the question. This is an alternative solution. Using a model to group the related information rather keeping two separate arrays in sync.
For more information on Structs and Classes check the documentation
struct Nationality {
var id: Int
var name: String
}
let nationalities = [
Nationality(id: 3, name: "Indian"),
Nationality(id: 4, name: "Philippines")
]
let randomNationalityIds = [3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4]
let nationalitiesResult = Set(randomNationalityIds).flatMap { id in
nationalities.filter({ id == $0.id }).first
}
print(nationalitiesResult)
Output: [__lldb_expr_136.Nationality(id: 4, name: "Philippines"), __lldb_expr_136.Nationality(id: 3, name: "Indian")]
You don't need to keep these in order because the id and name are in the same place.
Instead of creating a non-unique array first and reducing it to a unique array afterwards you could as well collect the nationality strings in a Set of Nationalities:
var nationalitySet = Set<String>()
...
for nationality in decodedNationalities {
nationalitySet.append(nationality)
}
A set won’t store any duplicates so if you add a nationality which is already contained it won’t be added again.
As the set is unordered but converting it into a sorted array is an easy one:
let nationalities = nationalitiesSet.sorted { $0.name < $1.name }
This solution does, however, require Nationality to be hashable, i. e. it must conform to the Hashable protocol:
struct Nationality: Hashable {
var name: String
var id: Int
}
Related
I have two arrays:
let a = ["apple","banana","orange","pomelo","kiwi","melon"]
let b = [1, 2, 4]
a contains all the items and b contains the indexes of the ones I'm interested in.
So I would like to create a function to extract the items at the indexes specified in array b.
I can do tis with for loops:
for i in 0...a.count-1{
if i == b[i]{
print(a[i])
}
}
To make it clear, the desired output would be:
banana orange kiwi
The problem is that with big numbers the for loop would be too slow.
I would like to know if there exists something with a lower complexity.
You can simply map the indices and return the associated elements:
let aa = ["apple","banana","orange","pomelo","kiwi","melon"]
let bb = [1, 2, 4]
let elements = bb.map { aa[$0] }
print(elements) // ["banana", "orange", "kiwi"]
Or extending RandomAccessCollection protocol:
extension RandomAccessCollection {
func elements(at indices: [Index]) -> [Element] { indices.map { self[$0] } }
}
let a = ["apple","banana","orange","pomelo","kiwi","melon"]
let b = [1, 2, 4]
let elements = a.elements(at: b) // ["banana", "orange", "kiwi"]
This question already has answers here:
In Swift how can I sort one array based on another array?
(4 answers)
Closed 4 years ago.
If I have:
var arrayOne = ["dog", "cat", "hamster", "horse"]
and
var arrayTwo = [3, 2, 4, 1]
How can I assign 3 to dog, 2 to cat, 4 to hamster, and 1 to horse so that if I sort arrayTwo from biggest integer to smallest, it will automatically do that for arrayOne too. In result it would print out:
var arrayOne = ["hamster", "dog", "cat", "horse"]
var arrayTwo = [4, 3, 2, 1]
What code is easiest and simplest for this?
Thanks in Advance! :)
It's quite hard to "bind" the two variables together. You could do something like this:
let dict = [3: "dog", 2: "cat", 4: "hamster", 1: "horse"]
var arrayTwo = [3, 2, 4, 1] {
willSet {
// you should probably check whether arrayTwo still has the same elements here
arrayOne = newValue.map { dict[$0]! }
}
}
It is easier to zip the arrays and then sort by arrayTwo:
let result = zip(arrayOne, arrayTwo).sorted(by: { $0.1 > $1.1 })
Now, result.map { $0.0 } is your sorted array 1 and result.map { $0.1 } is your sorted array 2.
I have two arrays for which I am comparing [Int]
let filter = strongAgainstArray.filter{weakAgainstArray.contains($0)}
This returns an array of common values in the 2 arrays. I then want to go through and remove those values from each array, which I'm doing like so
for item in filter {
for var i = 0; i < strongAgainstArray.count; i += 1 {
if item == strongAgainstArray[i] {
strongAgainstArray.removeAtIndex(i)
print("Removing a Strong against index \(item)")
}
}
for var i = 0; i < weakAgainstArray.count; i += 1 {
if item == weakAgainstArray[i] {
weakAgainstArray.removeAtIndex(i)
print("Removing a Weak against index \(item)")
}
}
}
This works fine, but let's say one of my arrays contains two entries for 12 as an example. How do I only remove one of them? As it stands, all entries of 12 are being removed entirely.
EDIT
I'm now comparing my two arrays using
let commonValues = Array(Set(strongAgainstArray).intersect(weakAgainstArray))
and then those commonValues from each array with
cleanStrongAgainstArray = Array(Set(strongAgainstArray).subtract(Set(commonValues)).sort())
cleanWeakAgainstArray = Array(Set(weakAgainstArray).subtract(Set(commonValues)).sort())
This is a much better overall solution, but I'm still eventually running into the same issue, albeit slightly different than before.
In the playground, for example...
let array = [7,7,9]
let test = Array(Set(array))
test comes back containing [7, 9], and I need to keep that extra 7. How do I do that?
If the order of the arrays aren't important then you can easily achieve the whole solution using Sets:
let dirtyArray = [1,4,6,1,56,4,4,66,23,3,3,12]
let dirtyArray1 = [3,1,6,99,54]
let cleanArray = Array(Set(dirtyArray).union(Set(dirtyArray1)))
print (cleanArray)
[12, 54, 23, 4, 6, 66, 99, 56, 1, 3]
If order is important, use NSOrderedSet:
let strongAgainstArray = [1, 2, 3, 4]
let weakAgainstArray = [3, 4, 5, 6]
let result = NSOrderedSet(array: (strongAgainstArray + weakAgainstArray)).array
I have two Int arrays, for example:
array1 = [1, 2, 3, 4] as Int
array2 = [10, 20, 30, 40] as Int
for work I need create Dictionary where Key - it's element from array1 and Value - it's element from array2, in my example - [1:10, 2:20, 3:30, 4:40] as [Int:Int].
So, when I create loop:
for i in 0..<arrayOfKeys.count {
dictionaryOfData[arrayOfKeys[i]] = arrayOfValues[i]
}
i see only last [4:40], but I know that I must have the Dictionary with 4 keys-values.
Give me, please, advise, how to do it in swift?!
upd, i find my problem - keys MUST be unique! So, thanks a lot for your answer and i knew about zip in swift
Try this:
let array1 = [1, 2, 3, 4]
let array2 = [10, 20, 30, 40]
var dict = [Int: Int]()
zip(array1, array2).forEach { dict[$0] = $1 }
print(dict)
Few solutions off the top of my head:
Init Arrays + Dict
let arrayOfValues = [1,2,3,4]
let arrayOfKeys = [1,2,3,4]
var arrayOfDict = [Int:Int]()
For loop solution:
for i in 0..<arrayOfKeys.count {
if i < arrayOfValues.count {
let key = arrayOfKeys[i]
let value = arrayOfValues[i]
arrayOfDict[key] = value
}
}
Using zip method solution:
for (key, value) in zip(arrayOfValues, arrayOfKeys) {
arrayOfDict[key] = value
}
From apple docs:
zip: A sequence of pairs built out of two underlying sequences, where
the elements of the ith pair are the ith elements of each underlying
sequence.(iOS (9.0 and later))
If you can't use Zip you can enumerate your array if both arrays have the same number of elements:
let array1 = [1, 2, 3, 4]
let array2 = [10, 20, 30, 40]
var result: [Int:Int] = [:]
array1.enumerate().forEach{ result[$0.element] = array2[$0.index] }
result // [2: 20, 3: 30, 1: 10, 4: 40]
Here is an updated answer for Swift 4 taken from www.tutorialspoint.com:
let cities = ["Delhi", "Bangalore", "Hyderabad"]
let distances = [2000, 10, 620]
let cityDistanceDict = Dictionary(uniqueKeysWithValues: zip(cities, distances))
var testarray = NSArray()
testarray = [1,2,2,3,4,5,3]
print(testarray)
testarray.removeObject(2)
I want to remove single object from multiple matching object like
myArray = [1,2,2,3,4,3]
When I remove
myArray.removeObject(2)
then both objects are deleted. I want remove only single object.
I tried to use many extension but no one is working properly. I have already used this link.
Swift 2
Solution when using a simple Swift array:
var myArray = [1, 2, 2, 3, 4, 3]
if let index = myArray.indexOf(2) {
myArray.removeAtIndex(index)
}
It works because .indexOf only returns the first occurence of the found object, as an Optional (it will be nil if object not found).
It works a bit differently if you're using NSMutableArray:
let nsarr = NSMutableArray(array: [1, 2, 2, 3, 4, 3])
let index = nsarr.indexOfObject(2)
if index < Int.max {
nsarr.removeObjectAtIndex(index)
}
Here .indexOfObject will return Int.max when failing to find an object at this index, so we check for this specific error before removing the object.
Swift 3
The syntax has changed but the idea is the same.
Array:
var myArray = [1, 2, 2, 3, 4, 3]
if let index = myArray.index(of: 2) {
myArray.remove(at: index)
}
myArray // [1, 2, 3, 4, 3]
NSMutableArray:
let myArray = NSMutableArray(array: [1, 2, 2, 3, 4, 3])
let index = myArray.index(of: 2)
if index < Int.max {
myArray.removeObject(at: index)
}
myArray // [1, 2, 3, 4, 3]
In Swift 3 we call index(of:) on both Array and NSMutableArray, but they still behave differently for different collection types, like indexOf and indexOfObject did in Swift 2.
Swift 5: getting index of the first occurrence
if let i = yourArray.firstIndex(of: yourObject) {
yourArray.remove(at: i)
}
If you want to remove all duplicate objects then you can use below code.
var testarray = NSArray()
testarray = [1,2,2,3,4,5,3]
let set = NSSet(array: testarray as [AnyObject])
print(set.allObjects)