BostonAreaHuman
BostonAreaHuman

Reputation: 1461

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.

Upvotes: 0

Views: 112

Answers (2)

matt
matt

Reputation: 534977

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

Upvotes: 2

Syed Qamar Abbas
Syed Qamar Abbas

Reputation: 3677

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

Upvotes: 1

Related Questions