Swift: Filter a Dictionary with Array as Value

Swift: Filter a Dictionary with Array as Value

Here's a solution that maps the values based on the search and then filters out the empty results.

var dictionary = ["a": ["aberration", "abc"], "b" : ["babel", "bereft"]]
var searchText = "aberration"
let filteredDictionary = dictionary.mapValues { $0.filter { $0.hasPrefix(searchText) } }.filter { !$0.value.isEmpty }
print(filteredDictionary)

Output:

["a": ["aberration"]]

swift 3 filter array of dictionaries by string value of key in dictionary

I hope I understood what you were asking. You mention an "array of dictionaries" but you don't actually have an array of dictionaries anywhere in the code you've posted.

As far as I can tell, you are asking how to find all the entries in the found array for which itemName equals the filterItemName property.

If so, all you should need to do is:

let foundItems = found.filter { $0.itemName == filterItemName }

That's it.


Some other ideas:

If you want to search for items where filterItemName is contained in the itemName, you could do something like this:

let foundItems = found.filter { $0.itemName.contains(filterItemName) }

You could also make use of the lowercased() function if you want to do case-insensitive search.

You could also return properties of your found elements into an array:

let foundIds = found.filter { $0.itemName == filterItemName }.map { $0.itemId }

Swift: is there an elegant way to filter a dictionary value (which is an array)?

You can use mapValues and then filter for the actual values

let output = i.mapValues { $0.filter { value in value < 7 } }

Filter Array of Dictionary Objects by key and last value of that specified key

This can be done by grouping the elements based on the inner dictionary key and then selecting the last element of each group

let selected = Dictionary(grouping: randomData, by: { $0.keys.first })
.compactMap { $0.value.last }

As suggested by @Alexander in the comments this can be solved more directly using Dictionary(_:uniqueKeysWith:)

let selected = Dictionary(randomData.flatMap { $0 }, uniquingKeysWith: {
return $0 > $1 ? $0 : $1
})

The two solutions yield a slightly different result, the first an array of dictionaries and the second one a dictionary as can be seen below

First solution: [[2: 0.5237581], [4: 0.5928725], [5: 0.32073426], [0: 0.3142548]]

Second solution: [0: 0.3142548, 5: 0.32073426, 4: 0.5928725, 2: 0.5237581]

Filter dictionary of array objects

I decided it was simplest to get this right by using an old fashioned for loop and filter each group separately

var filtered = [String: [People]]()

for (k, v) in dict {
let result = v.filter {$0.name.lowercased().contains("ata")}
if result.count > 0 {
filtered[k] = result
}
}

Note that if you want to keep all the groups in the result dictionary just skip the if result.count > 0 condition

Filter a dictionary with a nested dictionary in Swift 5

To give you some examples how to filter I created a set of data from the winner and runner up in the Champions League tournament. In the main dictionary the Int key correspond to the tournament's year. The dictionary inside has two keys: 1stPlace and 2ndPlace. So for example in 2018 Real Madrid defeated Liverpool, the dictionary will look like this:

2018: ["1stPlace": "Real Madrid",   "2ndPlace": "Liverpool"]

Assuming this structure the Data variable has the results from 2018 to 2011. If you want to know who won in 2018 you can do something like this:

filteredData = Data.filter { $0.key == 2018 }

If you want know when Real Madrid won you doo like this:

filteredData = Data.filter { $0.value["1stPlace"] == "Real Madrid" }

If you want to know when Real Madrid defeated Atlético Madrid you do it like this:

filteredData = Data.filter {
$0.value["2ndPlace"] == "Atlético Madrid" &&
$0.value["1stPlace"] == "Real Madrid"
}

When you have the results in filteredData you can do query the data in different ways: you can sort by year, you can extract just the years, etc.

The following code is the playground I used to test different kinds of queries:

import Foundation

typealias DictOfDicts = [Int : [String : String]]

var Data: DictOfDicts = [
2018:
["1stPlace": "Real Madrid", "2ndPlace": "Liverpool"],
2017:
["1stPlace": "Real Madrid", "2ndPlace": "Juventus"],
2016:
["1stPlace": "Real Madrid", "2ndPlace": "Atlético Madrid"],
2015:
["1stPlace": "Barcelona", "2ndPlace": "Juventus"],
2014:
["1stPlace": "Real Madrid", "2ndPlace": "Atlético Madrid"],
2013:
["1stPlace": "Bayern Munich", "2ndPlace": "Borussia Dortmund"],
2012:
["1stPlace": "Chelsea", "2ndPlace": "Bayern Munich"],
2011:
["1stPlace": "Barcelona", "2ndPlace": "Manchester United"]
]

var filteredData: DictOfDicts = [:]

print("Results from 2017 to present")
print("----------------------------")
filteredData = Data.filter { $0.key >= 2017 } // Filter from 2017 to present
filteredData
.sorted { $0.key > $1.key } // Sort by year
.forEach {
print("In \($0.key) \($0.value["1stPlace"]!) defeated \($0.value["2ndPlace"]!)")
}
print("")

print("Results before 2015")
print("----------------------------")
filteredData = Data.filter { $0.key < 2015 } // Filter before 2015
filteredData
.sorted { $0.key > $1.key } // Sort by year
.forEach {
print("In \($0.key) \($0.value["1stPlace"]!) defeated \($0.value["2ndPlace"]!)")
}
print("")

filteredData = Data.filter { $0.value["1stPlace"] == "Real Madrid" } // Filter Real Madrid won
var years = filteredData
.sorted { $0.key < $1.key } // Sort by year
.map { "\($0.key)" } // Convert year to string
.joined(separator: ", ") // Convert to comma separated single string
print("Real Madrid won in: \(years)")
print("")

filteredData = Data.filter { $0.value["2ndPlace"] == "Juventus" } // Filter Juventus lost
years = filteredData
.sorted { $0.key > $1.key } // Sort by year
.map { "\($0.key)" } // Convert year to string
.joined(separator: ", ") // Convert to comma separated single string
print("Juventus lost the final match in: \(years)")
print("")

filteredData = Data.filter {
$0.value["2ndPlace"] == "Atlético Madrid" &&
$0.value["1stPlace"] == "Real Madrid"
} // Filter Real Madrid defeated Atlético Madrid
years = filteredData
.sorted { $0.key > $1.key } // Sort by year
.map { "\($0.key)" } // Convert year to string
.joined(separator: ", ") // Convert to comma separated single string
print("Real Madrid defeated Atlético Madrid in: \(years)")
print()

let winnersAndChampionships =
Set(Data.map { $0.value["1stPlace"]! }) // Get winners' names
.map { winner in
(winner, Data.filter { $0.value["1stPlace"] == winner }.count)
} // Map for each winner the number of wins
.sorted { $0.1 > $1.1}
print("Number of Champions League's wins per team")
print("------------------------------------------")
winnersAndChampionships.forEach {
print("\($0.0): \($0.1)")
}

The playground's output is:

Results from 2017 to present
----------------------------
In 2018 Real Madrid defeated Liverpool
In 2017 Real Madrid defeated Juventus

Results before 2015
----------------------------
In 2014 Real Madrid defeated Atlético Madrid
In 2013 Bayern Munich defeated Borussia Dortmund
In 2012 Chelsea defeated Bayern Munich
In 2011 Barcelona defeated Manchester United

Real Madrid won in: 2014, 2016, 2017, 2018

Juventus lost the final match in: 2017, 2015

Real Madrid defeated Atlético Madrid in: 2016, 2014

Number of Champions League's wins per team
------------------------------------------
Real Madrid: 4
Barcelona: 2
Bayern Munich: 1
Chelsea: 1

Swift: Filter a dictionary key from a struct from an array, which is optional

It's not completely clear to me what you're attempting to do, however, this will filter your cases array to only Test objects that contain non-nil values in the message dictionary:

let nonNil = cases.filter { (test) -> Bool in
return Array(test.message.values).filter({ (value) -> Bool in
return value == nil
}).count <= 0
}

The variable nonNil now contains the Test objects where title is "2" and title is "4".

You could further filter that if you want a [tags:preview] dictionary. Something like this would do that:

let tags = nonNil.map( { $0.message} ).flatMap { $0 }.reduce([String:String]()) { (accumulator, current) -> [String:String] in
guard let key = current.key, let value = current.value else { return accumulator }
var accum = accumulator
accum.updateValue(value, forKey: key)
return accum
}

The tags dictionary now contains: ["tag1": "preview4", "tag2": "preview2"]

Swift filter and dictionaries

Just do it like this:

var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var underAge = namesAndAges.filter({ $0.value < 18 }) // [(key: "Fabien", value: 16)]

What you do is that you use $0.value in your filter.



Related Topics



Leave a reply



Submit