Как отфильтровать массив Swift по другому массиву Swift, зная, что элемент фильтра является последовательностью?скорость имеет значение - PullRequest
0 голосов
/ 04 октября 2018

У меня есть один массив Swift из 10 000 структур:

struct Book {
    var id: Int?
    var name: String?
    var pages: Int?
    var words: Int?
}

var firstArray: [Book] = [] // contains 10,000 elements

, и у меня есть второй массив Swift типа Int с 5000 элементами:

var secondArray: [Int] = [] // contains 5,000 elements

Я хочу отфильтроватьfirstArray, удалив все элементы в нем, где поле id (Book.id) не содержится во secondArray.

Зная, что Book.id уникален для каждого элемента в firstArray, а также в последовательности (от малого добольшой).например.1, 2, 3, 6, 8, 10, 14, 15, 16, 40, 50, 51 и т. Д. (Некоторые числа могут быть пропущены)

Второй массив также уникален и имеет последовательность (маленькийк большому)

Какой самый быстрый способ отфильтровать firstArray в Swift 4?

Зная, что массивы представляют собой последовательность, фильтрация должна стать быстрее, когда мы правильно обработаем массив?То есть, если мы находимся на полпути через firstArray, мы будем циклически проходить только половину firstArray в поисках совпадения в secondArray.То же самое для secondArray, так как массив будет уменьшаться каждый раз, когда мы находим совпадение.Это все имеет смысл?

Надеюсь, кто-то там знает, как это сделать.Я видел, как это делается на Android (Kotlin), но как это сделать в Swift?

Я думаю, что в Kotlin это так:

firstArray?.let { dataFirstArray ->
        secondArray?.let {
            firstArray = ArrayList(dataFirstArray.asSequence().filter { dataSecondArray -> dataSecondArray in it }.toList())
        }
    }

1 Ответ

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

Если id всегда существует, не делайте его необязательным.

struct Book {
    var id: Int
    var name: String?
    var pages: Int?
    var words: Int?
}

Самый простой способ фильтрации - это одна строка:

func filter1(firstArray:[Book],secondArray:[Int]) -> [Book]
{
    return firstArray.filter{secondArray.contains($0.id)}
}

Я также пытался сделатьиспользование того факта, что массивы отсортированы следующим образом:

func filter2(firstArray:[Book],secondArray:[Int]) -> [Book]
{
    var j = 0;

    return firstArray.filter{
        while(j < secondArray.count && secondArray[j] < $0.id)
        {
            j += 1
        }
        if(j < secondArray.count && $0.id == secondArray[j])
        {
            j += 1
            return true
        }
        return false
    }
}

Как было предложено в комментарии, я также попытался использовать Set:

func filter3(firstSet:Set<Book>,secondSet:Set<Int>) -> Set<Book>
{
    return firstSet.filter{secondSet.contains($0.id)}
}

Протестировано с помощью следующего кода:

var firstArray: [Book] = (0..<10000).map{Book(id: $0, name: nil, pages: nil, words: nil)}.filter {_ in Int.random(in: 0...1) == 0}
var secondArray: [Int] = (0..<10000).filter{_ in Int.random(in: 0...1) == 0}

var timestamp = Date().timeIntervalSince1970
let result1 = filter1(firstArray: firstArray, secondArray: secondArray)
print(Date().timeIntervalSince1970 - timestamp)

timestamp = Date().timeIntervalSince1970
let result2 = filter2(firstArray: firstArray, secondArray: secondArray)
print(Date().timeIntervalSince1970 - timestamp)

timestamp = Date().timeIntervalSince1970
let result3 = filter3(firstArray: firstArray, secondSet: Set(secondArray))
print(Date().timeIntervalSince1970 - timestamp)

результат теста:

2.687404155731201
0.0014042854309082031
0.002758026123046875

Надеюсь, эта помощь

...