简体   繁体   中英

Looking to use filter in swift to filter inner array of structs while not touching outer array

Here is a playground I created to attempt to create the correct filter: What I want to return is all of the outside structs and any inside array values which meet a "text" block which will be inbound from a search bar.

//: Playground - noun: a place where people can play

import UIKit
import Foundation

struct events{
    var title:String
    var unique:Int
    var swimmers_info:[swim_info]

}

struct swim_info{
    var name:String
    var team:String
}

var arrayEV:[events]
var si1:[swim_info]
var si2:[swim_info]

si1 = [
    swim_info(name:"Smith, John",team:"PHNX"),
        swim_info(name:"Tenay, Teresa",team:"CRIM")
]

si2 = [
    swim_info(name:"Test, Two",team:"PHNX"),
    swim_info(name:"Female, Swimmer",team:"SSA")
]


arrayEV = [
    events(title: "First Event",unique: 5,swimmers_info:si1),
    events(title: "Second Event",unique: 2,swimmers_info:si2)
]

//print(arrayEV)

var newarrayEV1 = arrayEV.filter({(value) -> Bool in
    return value.swimmers_info.contains(where: {$0.team == "SSA"})
})

var newarrayEV2 = arrayEV.map({$0.swimmers_info.filter({(value) -> Bool in
    return value.team == "SSA"
})})


print(newarrayEV1)

YEILDS [__lldb_expr_42.events(title: "Second Event", unique: 2, swimmers_info: [__lldb_expr_42.swim_info(name: "Test, Two", team: "PHNX"), __lldb_expr_42.swim_info(name: "Female, Swimmer", team: "SSA")])]

**Incorect becuase it yeilds only the second main struct an both sub structs

print("  ")
print(newarrayEV2   )

[[], [__lldb_expr_42.swim_info(name: "Female, Swimmer", team: "SSA")]]

Incorrect because drops all main struct information

print("11")

KINDA CORRECT

I can get the desired result with:

for (index,loop) in arrayEV.enumerated(){
    //print(String(describing: index))
    //print(loop.swimmers_info)
    var new_si = loop.swimmers_info.filter({(value) -> Bool in
        return value.team == "SSA"
    })
    //print(new_si)
    arrayEV[index].swimmers_info = new_si

}

however I'm not sure if this is the best way to attack this.

Create a method in your event class which check the text with inner array and with his own title and tells you that this class fall in match-case or not

struct events{
    var title:String
    var unique:Int
    var swimmers_info:[swim_info]

    func haveSameText(_ text: String) -> Bool {
        let filtersArray = swimmers_info.filter { (info) -> Bool in
            return info.name.lowercased() == text.lowercased()
        }
        return filtersArray.count >= 0 || text.lowercased() == title.lowercased()
    }
}

struct swim_info{
    var name:String
    var team:String
}

To filter event array on the base of some text use below method.

var eventArr = [events]()
var filteredArray = eventArr.filter { (event) -> Bool in
    return event.haveSameText("text")
}

Based on your suggested "solution", I think this is what you're after:

arrayEV = arrayEV.map {
    var ev = $0
    ev.swimmers_info = ev.swimmers_info.filter {$0.team == "SSA"}
    return ev
}

The reason for the rather clumsy-looking three-liner is that we cannot mutate a struct's property unless the reference to the struct itself is a var reference — but map provides us with a let reference ( $0 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM