Сортировка массивов по количеству совпадений - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь найти количество совпадений элементов массива между несколькими тестовыми массивами и одним контрольным массивом.После нахождения количества совпадений я хочу добавить тестовые массивы в другой массив, отсортированный по количеству совпадений между контрольным массивом и тестовым массивом.Например, тестовый массив с 3 совпадениями будет с индексом 0, 2 совпадения с индексом 1 и т. Д.

let controlArray = ["milk", "honey"]
let test1 = ["honey", "water"]
let test2 = ["milk", "honey", "eggs"]
var sortedArrayBasedOnMatches = [[String]]()

/*I want to append test1 and test2 to sortedArrayBasedOnMatches based on how many items 
test1 and test2 have in common with controlArray*/

/*in my example above, I would want sortedArrayBasedOnMatches to equal 
[test2, test1] since test 2 has two matches and test 1 only has one*/

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Это можно сделать очень функциональным и быстрым способом, написав конвейер для обработки входных массивов:

let sortedArrayBasedOnMatches = [test1, test2] // initial unsorted array
    .map { arr in (arr, arr.filter { controlArray.contains($0) }.count) } // making pairs of (array, numberOfMatches)
    .sorted { $0.1 > $1.1 } // sorting by the number of matches
    .map { $0.0 } // getting rid of the match count, if not needed

Обновление Как указано @ Carpsen90, Switf 5 поставляется споддержка count(where:), которая уменьшает количество кода, необходимого при первом вызове map().Решение, которое использует это, может быть записано в виде

// Swift 5 already has this, let's add it for current versions too
#if !swift(>=5)
extension Sequence {
    // taken from the SE proposal
    // https://github.com/apple/swift-evolution/blob/master/proposals/0220-count-where.md#detailed-design
    func count(where predicate: (Element) throws -> Bool) rethrows -> Int {
        var count = 0
        for element in self {
            if try predicate(element) {
                count += 1
            }
        }
        return count
    }
}
#endif

let sortedArrayBasedOnMatches = [test1, test2] // initial unsorted array
    .map { (arr: $0, matchCount: $0.count(where: controlArray.contains)) } // making pairs of (array, numberOfMatches)
    .sorted { $0.matchCount > $1.matchCount } // sorting by the number of matches
    .map { $0.arr } // getting rid of the match count, if not needed

Еще одно изменение стиля по сравнению с оригинальным решением состоит в использовании меток для компонентов кортежа, это делает код немного более понятным, нотакже немного более многословно.

0 голосов
/ 15 октября 2018

Это будет охватывать случай, когда элементы не уникальны в вашем контрольном массиве (например, молоко, молоко, мед ...) и с любым количеством тестовых массивов.

func sortedArrayBasedOnMatches(testArrays:[[String]], control: [String]) -> [[String]]{
var final = [[String]].init()
var controlDict:[String: Int] = [:]
var orderDict:[Int: [[String]]] = [:] // the value is a array of arrays because there could be arrays with the same amount of matches.
for el in control{
    if controlDict[el] == nil{
        controlDict[el] = 1
    }
    else{
        controlDict[el] = controlDict[el]! + 1
    }
}
for tArr in testArrays{
    var totalMatches = 0
    var tDict = controlDict
    for el in tArr{
        if tDict[el] != nil && tDict[el] != 0 {
            totalMatches += 1
            tDict[el] = tDict[el]! - 1
        }
    }
    if orderDict[totalMatches] == nil{
        orderDict[totalMatches] = [[String]].init()
    }
    orderDict[totalMatches]?.append(tArr)
}
for key in Array(orderDict.keys).sorted(by: >) {
    for arr in orderDict[key]! {
        final.append(arr)
    }
}
    return final
}
0 голосов
/ 12 октября 2018

Один из вариантов - преобразовать каждый массив в набор и найти количество элементов в пересечении с controlArray.

let controlArray = ["milk", "honey"]
let test1 = ["honey", "water"]
let test2 = ["milk", "honey", "eggs"]
var sortedArrayBasedOnMatches = [ test1, test2 ].sorted { (arr1, arr2) -> Bool in
    return Set(arr1).intersection(controlArray).count > Set(arr2).intersection(controlArray).count
}
print(sortedArrayBasedOnMatches)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...