简体   繁体   English

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

[英]In Swift how can I sort one array based on another array?

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.我知道我可以构建一个函数来完成它并可以跟踪索引,但我很好奇是否有更优雅的解决方案。

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 offset s, use map to extract the offsets , and then use map to order the other arrays:如果您有 3 个或更多数组要一起排序,则可以sort其中一个数组及其offset进行sort ,使用map提取offsets ,然后使用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"]

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 }

Swift 4斯威夫特 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.正如@Duncan C指出的那样,这种方法效率不高,因为第一个数组是重复排序的。 @vacawama's approach should be used instead, which in Swift 4 syntax is:应该改用@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]}

Though not especially elegant, a simple solution when working with arrays of objects which must be compared, and whose orders are not known and may not even share the same lengths , is to loop the "ordered" array, finding the matching object in the unordered array, and appending it to a new empty array:虽然没有特别的优雅,与对象数组必须进行比较,并且其命令没有已知的,并且可能甚至不共享相同的长度工作时,一个简单的解决办法是循环中的“有序”阵列,发现在无序匹配对象数组,并将其附加到一个新的空数组中:

var sorted: [Foo] = []

// Loop the collection whose order will define the other
for item in originalOrder {
    // Find the item in the unsorted collection
    if let next = unsortedItems.first(where: { $0 === item }) {
        // Move the item to the new collection, thus achieving order parity
        sorted.append(next)
    }
}

This is useful when you have an operation that provides a transformed version of a collection which may have 0..<original.count number of items in any order, and you want to get back to the original order using pointer/object equality.当您有一个操作提供集合的转换版本时,这可能很有用,该版本可能具有0..<original.count任何顺序的项目数,并且您想使用指针/对象相等性返回到原始顺序。

If you need to additionally maintain index parity, you can skip the if let and just append the result of first(where:) directly into sorted , which will put nil into the blanks.如果您需要额外维护索引奇偶校验,您可以跳过if let并将first(where:)的结果直接附加到sorted ,这会将nil放入空格中。

Note that this example solution will additionally act as a filter for items which are either duplicated or not in the original, which may or may not be what you want.请注意,此示例解决方案还将作为过滤器,用于过滤重复或不在原始文件中的项目,这些项目可能是您想要的,也可能不是。 Modify to your needs.根据您的需要进行修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM