Подтвердить что ты не робот

В Swift как я могу отсортировать один массив на основе другого массива?

В Swift говорят, что у меня есть два массива:

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

Теперь, я хочу сортировать массив1 в порядке возрастания и reindex array2 соответственно, чтобы получить

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

Есть ли простой способ сделать это с помощью функций Swift или синтаксиса?

Я знаю, что могу построить функцию, чтобы сделать это, и отслеживать индексы, но мне любопытно, есть ли более элегантное решение.

4b9b3361

Ответ 1

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]"

Сортировка более 2 массивов вместе

Если у вас есть 3 или более массивов для сортировки вместе, вы можете sort один из массивов вместе с его offset s, использовать 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)

Выход:

["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

Вы можете "связывать" элементы каждого массива путем сопоставления индексов для создания массива кортежей, а затем сортировать кортежи в соответствии с первыми значениями массива перед извлечением исходных массивов.

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

Swift 4

Эта часть переведена с @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]"

Вышеприведенная логика может быть расширена для трех или более массивов:

(медленный)

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}

Как отметил @Duncan C, этот подход не очень эффективен, поскольку первый массив сортируется неоднократно. Вместо этого следует использовать подход @vacawama, который в синтаксисе Swift 4:

(быстро)

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]}