Valeriy
Valeriy

Reputation: 743

Search array struct in an array in the struct

help me find an array in the array. In this implementation, I return the entire array.

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

I need to return:

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

// Playground

import UIKit

struct 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)

Upvotes: 1

Views: 98

Answers (3)

Abdelahad Darwish
Abdelahad Darwish

Reputation: 6067

You can use reduce also

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)

Upvotes: 0

David Pasztor
David Pasztor

Reputation: 54706

A simple filter won't help you achieve your goals, since you are trying to modify the test instances as well by filtering their arr property. You can use compactMap instead of filter to return modified test instances in case they fulfilled the filter criterion or nil if they didn't and compactMap will only keep the non-nil values.

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

Test data:

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(name: "Bell 2", arr: [__lldb_expr_1.ArrSub(sub_txt: "Test 2, 2"), __lldb_expr_1.ArrSub(sub_txt: "Test 2, 23")])]

You should conform to the Swift naming convention, which is UpperCamelCase for types, so I changed test to Test and arrSub to ArrSub.

Upvotes: 2

Valeriy
Valeriy

Reputation: 743

Thanks, @Dávid Pásztor. I just slightly corrected

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} 

This search will find only one record always in the substructure. But I need to return all the elements that are equal to the search condition.

Upvotes: 0

Related Questions