Naveen George Thoppan
Naveen George Thoppan

Reputation: 571

Swift - Joining two tuple arrays based on their values

I've a scenario where I have two arrays of tuples.

tuple1 = [(score1, index1), (score2, index2), (score3, index3)]
tuple2 = [(date1, index1), (date2, index2), (date3, index4)]

I want to get the scores and dates from these tuples and create a new array of tuples such that it contains the score and date having the same index like this:

tuple3 = [(score1, date1), (score2, date2)]

How can I implement this? What is the best practice to follow in this scenario? Note: The arrays can be of different sizes

My implementation for the scenario is as follows:

var tuple3 = [(Double, Date)]()
    for (i,psa) in tuple1.enumerated() {

        let date = tuple2.filter({ $0.1 == i })

        if date.count == 1 {
            let newTuple = (tuple1.0, date[0].0)
            tuple3.append(newTuple)
        }
    }

Is this a right way to do it or is there a better one?

Upvotes: 0

Views: 866

Answers (4)

XmasRights
XmasRights

Reputation: 1509

let tuple1 = [("score1", "index1"), ("score2", "index2"), ("score3", "index3")]
let tuple2 = [("date1", "index1"), ("date2", "index2"), ("date3", "index4")]

let t2Dict = tuple2.reduce(into: [String:String]()) { (dict, args) in
    let (date, index) = args
    dict[index] = date
}

let tuple3 = tuple1.compactMap { args -> (String, String)? in
    let (score, index) = args
    guard let date = t2Dict[index] else { return nil }
    return (score, date)
}

It's not as pretty as the others, but it's far more efficient to collapse one of the tuples into a dictionary first.

Upvotes: 2

ielyamani
ielyamani

Reputation: 18591

This might be what you're looking for:

let tuple1 = [("score1", "index1"), ("score2", "index2"), ("score3", "index3")]
let tuple2 = [("date1", "index1"), ("date2", "index2"), ("date3", "index4")]

let filtered = tuple1.filter {tuple2.map{$0.1}.contains($0.1)}
let result = filtered.map {tuple in
    return (tuple.0, tuple2.first(where: {$0.1 == tuple.1})!.0)
}

print (result)  // [("score1", "date1"), ("score2", "date2")]

I'm using Strings for simplicity, just make sure you are using Equatable objects in your tuples.

Upvotes: 0

Larme
Larme

Reputation: 26036

This should do the trick:

let tuple3 = tuple1.compactMap({  (scoreInTuple1, indexInTuple1) -> (String, String)? in
    if let tupleIn2 = tuple2.first(where: { (scoreInTuple2, index2InTuple2) in index2InTuple2 == indexInTuple1 }){
        return (scoreInTuple1, tupleIn2.0)
    }
    return nil
})

(String, String) should be change to the real type/class of score & date1. Also, index2InTuple2 == indexInTuple1 might be changed also if it's custom type/class which might not be Equatable.

With sample code before:

let tuple1 = [("score1", "index1"), ("score2", "index2"), ("score3", "index3")]
let tuple2 = [("date1", "index1"), ("date2", "index2"), ("date3", "index4")]

Debug log after:

print("tuple3: \(tuple3)")

Output:

$> tuple3: [("score1", "date1"), ("score2", "date2")]

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100523

You can try

let v1 = [("1","2"),("3","4")]

let v2 = [("1A","2A"),("3A","4A")]

let res = zip(v1,v2).map { ($0.0 , $1.0) } // [("1", "1A"), ("3", "3A")]

print(res)

Upvotes: 3

Related Questions