Поиск массива в массиве в структуре

Valeriy спросил: 28 апреля 2018 в 09:30 в: swift

Помогите мне найти массив в массиве. В этой реализации я возвращаю весь массив.

[(name: "Bell 2", arr: [arrSub(sub_txt: "Test 2, 1"),arrSub(sub_txt: "Test 2, 2")])]

Мне нужно вернуть:

[(name: "Bell 2", arr: [arrSub(sub_txt: "Test 2, 2")])]

// Playground

import UIKitstruct arrSub {
    let sub_txt: String
}struct test {
    let name: String
    let arr: [arrSub]    init(name: String, arr: [arrSub]) {
        self.name = name
        self.arr  = arr
    }
}var testArr = [test]()testArr.append(test(name: "Line 1", arr: [arrSub(sub_txt: "Line 1, 1"), arrSub(sub_txt: "Line 1, 2")]))
testArr.append(test(name: "Bell 2", arr: [arrSub(sub_txt: "Bell 2, 1"), arrSub(sub_txt: "Bell 2, 2")]))
testArr.append(test(name: "Bell 2", arr: [arrSub(sub_txt: "Test 2, 1"), arrSub(sub_txt: "Test 2, 2")]))let new = testArr.filter({
    $0.arr.contains(where: { $0.sub_txt.contains("Test 2, 2") } )        
})print(new)

3 ответа

Есть решение
Dávid Pásztor ответил: 28 апреля 2018 в 10:34

Простой filter не поможет вам достичь ваших целей, так как вы пытаетесь изменить экземпляры test, а также фильтруя их свойство arr. Вы можете использовать compactMap вместо filter, чтобы вернуть измененные экземпляры test, если они выполнили критерий filter или nil если они этого не сделали, и compactMap будет сохранять только значения, отличные от нуля.

let new = testArr.compactMap({ test->Test? in
let foundArrSub = test.arr.filter({ $0.sub_txt.contains("Test 2, 2") })
    if foundArrSub.count > 0 {
        return Test(name: test.name, arr: foundArrSub)
    }
    return nil
})

Данные теста:

var testArr = [Test]()testArr.append(Test(name: "Line 1", arr: [ArrSub(sub_txt: "Line 1, 1"), ArrSub(sub_txt: "Line 1, 2")]))
testArr.append(Test(name: "Bell 2", arr: [ArrSub(sub_txt: "Bell 2, 1"), ArrSub(sub_txt: "Bell 2, 2")]))
testArr.append(Test(name: "Bell 2", arr: [ArrSub(sub_txt: "Test 2, 1"), ArrSub(sub_txt: "Test 2, 2"),ArrSub(sub_txt: "Test 2, 23")]))

[__ lldb_expr_1.Test (имя: "Bell 2", arr: [__lldb_expr_1.ArrSub (sub_txt: "Test 2, 2"), __lldb_expr_1.ArrSub (sub_txt: "Test 2, 23")] )]

Вам следует соблюдать соглашение об именах Swift, которое является UpperCamelCase для типов, поэтому я изменил test на Test и arrSub до ArrSub.

Valeriy ответил: 28 апреля 2018 в 10:28
Этот поиск найдет только одну запись всегда в подструктуре. Но мне нужно вернуть все элементы, равные условию поиска.
Dávid Pásztor ответил: 28 апреля 2018 в 10:34
@Valeriy проверить мой обновленный ответ.
Valeriy ответил: 28 апреля 2018 в 10:29

Спасибо, @ Dávid Pásztor. Я просто немного исправил

let new = testArr.compactMap { (myTest) -> test? in
if let foundArrSub = myTest.arr.first(where: { $0.sub_txt.contains("Test 2, 2") }){
    return test(name: myTest.name, arr: [foundArrSub])
}
return nil} 

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

TheTiger ответил: 28 апреля 2018 в 10:13
Почему вы опубликовали тот же фрагмент кода, на который уже был дан ответ?
Abdelahad Darwish ответил: 28 апреля 2018 в 11:03

Вы можете использовать reduce также

let news =  testArr.reduce([test]()) { (result, testObj) -> [test] in            let internalArray  = testObj.arr.filter({ (arraySub) -> Bool in
                return   arraySub.sub_txt.range(of:"Test 2, 2") != nil
            }).filter({ (arraySub) -> Bool in
                return   arraySub.sub_txt.range(of:"Test 2, 2") != nil
            })
        if internalArray.count > 0 {
            return result + [test.init(name: testObj.name, arr: internalArray)]
        }else{
            return result
        }
    }    print(news)