How to sort 1 array in Swift / Xcode and reorder multiple other arrays by the same keys changes
You could create an array of indexes in sorted order and use it as a mapping:
var names = [ "Paul", "John", "David" ]
var ages = [ 35, 42, 27 ]
let newOrder = names.enumerate().sort({$0.1<$1.1}).map({$0.0})
names = newOrder.map({names[$0]})
ages = newOrder.map({ages[$0]})
[EDIT] Here's an improvement on the technique :
It's the same approach but does the sorting and assignment in one step.
(can be reassigned to original arrays or to separate ones)
(firstNames,ages,cities,countries,actives) =
{(
$0.map{firstNames[$0]},
$0.map{ages[$0]},
$0.map{cities[$0]},
$0.map{countries[$0]},
$0.map{actives[$0]}
)}
(firstNames.enumerated().sorted{$0.1<$1.1}.map{$0.0})
[EDIT2] and an Array extension to make it even easier to use if you are sorting in place:
extension Array where Element:Comparable
{
func ordering(by order:(Element,Element)->Bool) -> [Int]
{ return self.enumerated().sorted{order($0.1,$1.1)}.map{$0.0} }
}
extension Array
{
func reorder<T>(_ otherArray:inout [T]) -> [Element]
{
otherArray = self.map{otherArray[$0 as! Int]}
return self
}
}
firstNames.ordering(by: <)
.reorder(&firstNames)
.reorder(&ages)
.reorder(&cities)
.reorder(&countries)
.reorder(&actives)
combining the previous two:
extension Array
{
func reordered<T>(_ otherArray:[T]) -> [T]
{
return self.map{otherArray[$0 as! Int]}
}
}
(firstNames,ages,cities,countries,actives) =
{(
$0.reordered(firstNames),
$0.reordered(ages),
$0.reordered(cities),
$0.reordered(countries),
$0.reordered(actives)
)}
(firstNames.ordering(by:<))
Sorting a Swift array by ordering from another array
Edit: My original approach was shit. This post got a lot of traction, so it's time to give it some more attention and improve it.
Fundamentally, the problem is easy. We have two elements, and we have an array (or any ordered Collection
) whose relative ordering determines their sort order. For every element, we find its position in the ordered collection, and compare the two indices to determine which is "greater".
However, if we naively do linear searches (e.g. Array.firstIndex(of:)
), we'll get really bad performance (O(array.count)
), particularly if the fixed ordering is very large. To remedy this, we can construct a Dictionary
, that maps elements to their indices. The dictionary provides fast O(1)
look-ups, which is perfect for the job.
This is exactly what HardCodedOrdering
does. It pre-computes a dictionary of elements to their orderings, and provides an interface to compare 2 elements. Even better, it can be configured to respond differently to encountering elements with an unknown ordering. It could put them first before everything else, last after everything else, or crash entirely (the default behaviour).
HardCodedOrdering
public struct HardCodedOrdering<Element> where Element: Hashable {
public enum UnspecifiedItemSortingPolicy {
case first
case last
case assertAllItemsHaveDefinedSorting
}
private let ordering: [Element: Int]
private let sortingPolicy: UnspecifiedItemSortingPolicy
public init(
ordering: Element...,
sortUnspecifiedItems sortingPolicy: UnspecifiedItemSortingPolicy = .assertAllItemsHaveDefinedSorting
) {
self.init(ordering: ordering, sortUnspecifiedItems: sortingPolicy)
}
public init<S: Sequence>(
ordering: S,
sortUnspecifiedItems sortingPolicy: UnspecifiedItemSortingPolicy = .assertAllItemsHaveDefinedSorting
) where S.Element == Element {
self.ordering = Dictionary(uniqueKeysWithValues: zip(ordering, 1...))
self.sortingPolicy = sortingPolicy
}
private func sortKey(for element: Element) -> Int {
if let definedSortKey = self.ordering[element] { return definedSortKey }
switch sortingPolicy {
case .first: return Int.min
case .last: return Int.max
case .assertAllItemsHaveDefinedSorting:
fatalError("Found an element that does not have a defined ordering: \(element)")
}
}
public func contains(_ element: Element) -> Bool {
return self.ordering.keys.contains(element)
}
// For use in sorting a collection of `T`s by the value's yielded by `keyDeriver`.
// A throwing varient could be introduced, if necessary.
public func areInIncreasingOrder<T>(by keyDeriver: @escaping (T) -> Element) -> (T, T) -> Bool {
return { lhs, rhs in
self.sortKey(for: keyDeriver(lhs)) < self.sortKey(for: keyDeriver(rhs))
}
}
// For use in sorting a collection of `Element`s
public func areInIncreasingOrder(_ lhs: Element, rhs: Element) -> Bool {
return sortKey(for: lhs) < sortKey(for: rhs)
}
}
Example usage:
let rankOrdering = HardCodedOrdering(ordering: "Private", "Lieutenant", "Captain", "Admiral") // ideally, construct this once, cache it and share it
let someRanks = [
"Admiral", // Should be last (greatest)
"Gallactic Overlord", // fake, should be removed
"Private", // Should be first (least)
]
let realRanks = someRanks.lazy.filter(rankOrdering.contains)
let sortedRealRanks = realRanks.sorted(by: rankOrdering.areInIncreasingOrder) // works with mutating varient, `sort(by:)`, too.
print(sortedRealRanks) // => ["Private", "Admiral"]
Swift2 - Sort multiple arrays based on the sorted order of another INT array
Create a new array of indexes sorted the way you want "descending" and then map the other arrays.
var points:[Int] = [200, 1000, 100, 500]
var people:[String] = ["Harry", "Jerry", "Hannah", "John"]
var peopleIds:[Int] = [1, 2, 3, 4]
var sex:[String] = ["Male", "Male", "Female", "Male"]
//descending order array of indexes
let sortedOrder = points.enumerate().sort({$0.1>$1.1}).map({$0.0})
//Map the arrays based on the new sortedOrder
points = sortedOrder.map({points[$0]})
people = sortedOrder.map({people[$0]})
peopleIds = sortedOrder.map({peopleIds[$0]})
sex = sortedOrder.map({sex[$0]})
I just tested this solution out and it works well.
Swift - Sort array of objects with multiple criteria
Think of what "sorting by multiple criteria" means. It means that two objects are first compared by one criteria. Then, if those criteria are the same, ties will be broken by the next criteria, and so on until you get the desired ordering.
let sortedContacts = contacts.sort {
if $0.lastName != $1.lastName { // first, compare by last names
return $0.lastName < $1.lastName
}
/* last names are the same, break ties by foo
else if $0.foo != $1.foo {
return $0.foo < $1.foo
}
... repeat for all other fields in the sorting
*/
else { // All other fields are tied, break ties by last name
return $0.firstName < $1.firstName
}
}
What you're seeing here is the Sequence.sorted(by:)
method, which consults the provided closure to determine how elements compare.
If your sorting will be used in many places, it may be better to make your type conform to the Comparable
protocol. That way, you can use Sequence.sorted()
method, which consults your implementation of the Comparable.<(_:_:)
operator to determine how elements compare. This way, you can sort any Sequence
of Contact
s without ever having to duplicate the sorting code.
Sorting 2 arrays the same way in swift
Given
let prices = [9, 4, 1]
let names = ["item 1", "item 2", "item 3"]
Solution #1
You can
let sorted = zip(prices, names).sorted { $0.0 < $1.0 }
let sortedPrices = sorted.map { $0.0 } // [1, 4, 9]
let sortedNames = sorted.map { $0.1 } // ["item 3", "item 2", "item 1"]
Solution #2
You should really use a model value.
let prices = [9, 4, 1]
let names = ["item 1", "item 2", "item 3"]
struct Item {
let name: String
let price: Int
}
let sortedItems = zip(names, prices).map(Item.init).sorted { $0.price < $1.price }
// [Item(name: "item 3", price: 1), Item(name: "item 2", price: 4), Item(name: "item 1", price: 9)]
Swift : Sorting three arrays based on a particular array
First of all in Swift we should not name a variable (or constant) after its type, so:
let codes = ["de_DE", "en_US", "en-GB", "es_ES"]
let locales = ["Deutsch", "English", "English UK", "Español"]
let internationals = ["German", "English", "British English", "Spanish"]
Now let's build an array of indexes looking at how codes
should be sorted
let indexes = codes.enumerate().sort { $0.element < $1.element }.map { $0.index }
The
indexes
array contains[0, 2, 1, 3]
, thei-th
element into this array represents the position thei-th
ofcodes
should have.
So now we can sort each array based on indexes
let sortedCodes = codes.enumerate().sort { indexes[$0.0] < indexes[$1.0] }.map { $0.element }
let sortedLocales = locales.enumerate().sort { indexes[$0.0] < indexes[$1.0] }.map { $0.element }
let sortedInternationals = internationals.enumerate().sort { indexes[$0.0] < indexes[$1.0] }.map { $0.element }
Output
sortedCodes // ["de_DE", "en-GB", "en_US", "es_ES"]
sortedLocales // ["Deutsch", "English UK", "English", "Español"]
sortedInternationals // ["German", "British English", "English", "Spanish"]
That's it.
Reorder array compared to another array in Swift
You can sort objects
in order to follow the order in ids
writing
let sorted = objects.sort { ids.indexOf($0.id) < ids.indexOf($1.id) }
// [{id "1"}, {id "2"}, {id "3"}]
Another example
let ids: [String] = ["3", "2", "1"]
let objects: [MyObject] = [MyObject(id: "3"), MyObject(id: "1"), MyObject(id: "2")]
let sorted = objects.sort { ids.indexOf($0.id) < ids.indexOf($1.id) }
// [{id "3"}, {id "2"}, {id "1"}]
This code is in Swift 2.2
Swift 4.2 solution
let sorted = objects.sorted { ids.index(of: $0.id)! < ids.index(of: $1.id)! }
How to sort an array of custom objects by property value in Swift
First, declare your Array as a typed array so that you can call methods when you iterate:
var images : [imageFile] = []
Then you can simply do:
Swift 2
images.sorted({ $0.fileID > $1.fileID })
Swift 3
images.sorted(by: { $0.fileID > $1.fileID })
Swift 5
images.sorted { $0.fileId > $1.fileID }
The example above gives the results in descending order.
Related Topics
Disable Warning Dialog If Bluetooth Is Powered Off iOS
Cordova Xcode Build Failed "Permission Denied"
How to Get MAC Address from Cbperipheral and Cbcenter
Fbsopenapplicationerrordomain Code=3
Xamarin "The Executable Was Signed with Invalid Entitlements"
How to Monitor Battery Level and State Changes Using Swift
Dequeuereusablecellwithidentifier:Forindexpath: VS Dequeuereusablecellwithidentifier:
Recording from Remoteio: Resulting .Caf Is Pitch Shifted Slower + Distorted
Insert String at Cursor Position of Uitextfield
Rec iOS Conversations. Where to Start
How to Evaluate the String Equation in iOS
iOS App Getting Throttled from Local Searches
A Lighter Way of Discovering Text Writing Direction
Why Was Uitextfield's Text Property Changed to an Optional in Swift 2