在Swift中,如何根据另一个数组对一个数组进行排序?

时间:2022-09-25 08:54:05

In Swift, say I have two arrays:

在Swift中,假设我有两个数组:

var array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
var array2: [Int] = [1, 0, 2, 0, 3]

Now, I want to sort array1 in ascending order and reindex array2 accordingly so that I get

现在,我想按升序对array1进行排序,并相应地重新索引array2以便得到

array1 = [1.2, 1.5, 2.4, 10.9, 20.4]
array2 = [1, 3, 0, 0, 2]

Is there a simple way to do this using Swift functions or syntax?

使用Swift函数或语法有一种简单的方法吗?

I know I can build a function to do it and can keep track of indices, but I'm curious if there is a more elegant solution.

我知道我可以构建一个函数来完成它并且可以跟踪索引,但我很好奇是否有更优雅的解决方案。

3 个解决方案

#1


31  

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]

// use zip to combine the two arrays and sort that based on the first    
let combined = zip(array1, array2).sorted {$0.0 < $1.0}
print(combined) // "[(1.2, 1), (1.5, 3), (2.4, 0), (10.9, 0), (20.0, 2)]"

// use map to extract the individual arrays    
let sorted1 = combined.map {$0.0}
let sorted2 = combined.map {$0.1}

print(sorted1)  // "[1.2, 1.5, 2.4, 10.9, 20.0]"
print(sorted2)  // "[1, 3, 0, 0, 2]"

Sorting more than 2 arrays together

将两个以上的阵列排序在一起

If you have 3 or more arrays to sort together, you can sort one of the arrays along with its offsets, use map to extract the offsets, and then use map to order the other arrays:

如果要将3个或更多阵列排序在一起,可以对其中一个阵列及其偏移进行排序,使用map提取偏移量,然后使用map命令其他阵列:

let english = ["three", "five", "four", "one", "two"]
let ints = [3, 5, 4, 1, 2]
let doubles = [3.0, 5.0, 4.0, 1.0, 2.0]
let roman = ["III", "V", "IV", "I", "II"]

// Sort english array in alphabetical order along with its offsets
// and then extract the offsets using map
let offsets = english.enumerated().sorted { $0.element < $1.element }.map { $0.offset }

// Use map on the array of ordered offsets to order the other arrays
let sorted_english = offsets.map { english[$0] }
let sorted_ints = offsets.map { ints[$0] }
let sorted_doubles = offsets.map { doubles[$0] }
let sorted_roman = offsets.map { roman[$0] }

print(sorted_english)
print(sorted_ints)
print(sorted_doubles)
print(sorted_roman)

Output:

输出:

["five", "four", "one", "three", "two"]
[5, 4, 1, 3, 2]
[5.0, 4.0, 1.0, 3.0, 2.0]
["V", "IV", "I", "III", "II"]

#2


7  

You could "link" the items of each array by mapping over the indices to create an array of tuples, then sort the tuples according to the first array's values before extracting the original arrays.

您可以通过映射索引来“链接”每个数组的项目以创建元组数组,然后在提取原始数组之前根据第一个数组的值对元组进行排序。

assert(array1.count == array2.count, "The following technique will only work if the arrays are the same length.")
let count = array1.count

// Create the array of tuples and sort according to the
// first tuple value (i.e. the first array)
let sortedTuples = (0..<count).map { (array1[$0], array2[$0]) }.sort { $0.0 < $1.0 }

// Map over the sorted tuples array to separate out the
// original (now sorted) arrays.
let sortedArray1 = sortedTuples.map { $0.0 }
let sortedArray2 = sortedTuples.map { $0.1 }

#3


2  

Swift 4

This part is translated from @vacawama's answer to Swift 4 syntax

本部分由@ vacawama对Swift 4语法的回答翻译而来

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]

// use zip to combine the two arrays and sort that based on the first    
let combined = zip(array1, array2).sorted(by: {$0.0 < $1.0})
print(combined) // "[(1.2, 1), (1.5, 3), (2.4, 0), (10.9, 0), (20.0, 2)]"

// use map to extract the individual arrays    
let sorted1 = combined.map {$0.0}
let sorted2 = combined.map {$0.1}

print(sorted1)  // "[1.2, 1.5, 2.4, 10.9, 20.0]"
print(sorted2)  // "[1, 3, 0, 0, 2]"

The above logic can be expanded for three or more arrays:

上述逻辑可以扩展为三个或更多阵列:

(slow)

(慢)

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]
let array3: [Float] = [3.3, 1.1, 2.5, 5.1, 9.0]

// use zip to combine each (first, n.th) array pair and sort that based on the first    
let combined12 = zip(array1, array2).sorted(by: {$0.0 < $1.0})
let combined13 = zip(array1, array3).sorted(by: {$0.0 < $1.0})

// use map to extract the individual arrays    
let sorted1 = combined12.map {$0.0}
let sorted2 = combined12.map {$0.1}
let sorted3 = combined13.map {$0.1}

As @Duncan C pointed out, this approach is not very efficient as the first array is sorted repeatedly. @vacawama's approach should be used instead, which in Swift 4 syntax is:

正如@Duncan C指出的那样,这种方法效率不高,因为第一个数组是重复排序的。应该使用@vacawama的方法,在Swift 4语法中是:

(fast)

(快速)

let offsets = array1.enumerated()sorted(by: {$0.element < $1.element}).map {$0.offset}
let sorted1 = offsets.map {array1[$0]}
let sorted2 = offsets.map {array2[$0]}
let sorted3 = offsets.map {array3[$0]}

#1


31  

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]

// use zip to combine the two arrays and sort that based on the first    
let combined = zip(array1, array2).sorted {$0.0 < $1.0}
print(combined) // "[(1.2, 1), (1.5, 3), (2.4, 0), (10.9, 0), (20.0, 2)]"

// use map to extract the individual arrays    
let sorted1 = combined.map {$0.0}
let sorted2 = combined.map {$0.1}

print(sorted1)  // "[1.2, 1.5, 2.4, 10.9, 20.0]"
print(sorted2)  // "[1, 3, 0, 0, 2]"

Sorting more than 2 arrays together

将两个以上的阵列排序在一起

If you have 3 or more arrays to sort together, you can sort one of the arrays along with its offsets, use map to extract the offsets, and then use map to order the other arrays:

如果要将3个或更多阵列排序在一起,可以对其中一个阵列及其偏移进行排序,使用map提取偏移量,然后使用map命令其他阵列:

let english = ["three", "five", "four", "one", "two"]
let ints = [3, 5, 4, 1, 2]
let doubles = [3.0, 5.0, 4.0, 1.0, 2.0]
let roman = ["III", "V", "IV", "I", "II"]

// Sort english array in alphabetical order along with its offsets
// and then extract the offsets using map
let offsets = english.enumerated().sorted { $0.element < $1.element }.map { $0.offset }

// Use map on the array of ordered offsets to order the other arrays
let sorted_english = offsets.map { english[$0] }
let sorted_ints = offsets.map { ints[$0] }
let sorted_doubles = offsets.map { doubles[$0] }
let sorted_roman = offsets.map { roman[$0] }

print(sorted_english)
print(sorted_ints)
print(sorted_doubles)
print(sorted_roman)

Output:

输出:

["five", "four", "one", "three", "two"]
[5, 4, 1, 3, 2]
[5.0, 4.0, 1.0, 3.0, 2.0]
["V", "IV", "I", "III", "II"]

#2


7  

You could "link" the items of each array by mapping over the indices to create an array of tuples, then sort the tuples according to the first array's values before extracting the original arrays.

您可以通过映射索引来“链接”每个数组的项目以创建元组数组,然后在提取原始数组之前根据第一个数组的值对元组进行排序。

assert(array1.count == array2.count, "The following technique will only work if the arrays are the same length.")
let count = array1.count

// Create the array of tuples and sort according to the
// first tuple value (i.e. the first array)
let sortedTuples = (0..<count).map { (array1[$0], array2[$0]) }.sort { $0.0 < $1.0 }

// Map over the sorted tuples array to separate out the
// original (now sorted) arrays.
let sortedArray1 = sortedTuples.map { $0.0 }
let sortedArray2 = sortedTuples.map { $0.1 }

#3


2  

Swift 4

This part is translated from @vacawama's answer to Swift 4 syntax

本部分由@ vacawama对Swift 4语法的回答翻译而来

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]

// use zip to combine the two arrays and sort that based on the first    
let combined = zip(array1, array2).sorted(by: {$0.0 < $1.0})
print(combined) // "[(1.2, 1), (1.5, 3), (2.4, 0), (10.9, 0), (20.0, 2)]"

// use map to extract the individual arrays    
let sorted1 = combined.map {$0.0}
let sorted2 = combined.map {$0.1}

print(sorted1)  // "[1.2, 1.5, 2.4, 10.9, 20.0]"
print(sorted2)  // "[1, 3, 0, 0, 2]"

The above logic can be expanded for three or more arrays:

上述逻辑可以扩展为三个或更多阵列:

(slow)

(慢)

let array1: [Double] = [1.2, 2.4, 20.0, 10.9, 1.5]
let array2: [Int] = [1, 0, 2, 0, 3]
let array3: [Float] = [3.3, 1.1, 2.5, 5.1, 9.0]

// use zip to combine each (first, n.th) array pair and sort that based on the first    
let combined12 = zip(array1, array2).sorted(by: {$0.0 < $1.0})
let combined13 = zip(array1, array3).sorted(by: {$0.0 < $1.0})

// use map to extract the individual arrays    
let sorted1 = combined12.map {$0.0}
let sorted2 = combined12.map {$0.1}
let sorted3 = combined13.map {$0.1}

As @Duncan C pointed out, this approach is not very efficient as the first array is sorted repeatedly. @vacawama's approach should be used instead, which in Swift 4 syntax is:

正如@Duncan C指出的那样,这种方法效率不高,因为第一个数组是重复排序的。应该使用@vacawama的方法,在Swift 4语法中是:

(fast)

(快速)

let offsets = array1.enumerated()sorted(by: {$0.element < $1.element}).map {$0.offset}
let sorted1 = offsets.map {array1[$0]}
let sorted2 = offsets.map {array2[$0]}
let sorted3 = offsets.map {array3[$0]}