Filtering an Array Inside a Dictionary - Swift

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: 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"]]

Filtering an Array inside a Dictionary - Swift

The main problem is that you are using a dictionary as data source array.

My suggestion is to use a custom struct as model

struct Contact {
let letter : String
var clients : [Client]

init(letter: String, clients : [Client] = [Client]()) {
self.letter = letter
self.clients = clients
}

mutating func add(client : Client) {
clients.append(client)
}
}

Then create your data source array

var contacts = [Contact]()  

and the letter array as computed property

var letters : [String] = {
return contacts.map{ $0.letter }
}

It's easy to sort the array by letter

contacts.sort{ $0.letter < $1.letter }

Now you can search / filter this way (text is the text to be searched for)

 filteredClient.removeAll()
for contact in contacts {
let filteredContent = contact.clients.filter {$0.name.range(of: text, options: [.anchored, .caseInsensitive, .diacriticInsensitive]) != nil }
if !filteredContent.isEmpty {
filteredClient.append(filteredContent)
}
}

You can even keep the sections (letters) if you declare filteredClient also as [Contact] and create temporary Contact instances with the filtered items.

Of course you need to change all table view data source / delegate methods to conform to the Contact array, but it's worth it. An array as data source is more efficient than a dictionary.

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 array of dictionaries - SWIFT

let test = [["user1ID": NSDate()], ["user2ID": NSDate()], ["user3ID": NSDate()]]
let newArray = test.filter { $0.keys.contains("user2ID") }.flatMap { $0 }

print(newArray) // ["user2ID": 2016-01-28 10:52:29 +0000]

I've edited your dictionary a bit for testing purposes.

Answer to your comment:

If you simply want to know if the array contains a dictionary with "user2ID" as key you can do the following:

test.contains { $0.keys.contains("user2ID") } ? print("yep!") : print("nope!") // "Yep!"

Chaining filter and map array by dictionary values in Swift

Assuming Object is a struct, based on the error message...

This just shows that higher-order functions shouldn't be used everywhere. map transforms each element in a sequence into something else. So instead of assigning score, you need to return a new Object with its score changed.

var scoresAssigned = filteredObjects.map { $0.withScore(scoreDict[$0.id.uuidString.lowercased()]) }

withScore will look something like:

func withScore(_ score: Int) -> Object {
var copy = self
copy.score = score
return copy
}

But, if you just want to assign the score a new value, I recommend a simple for loop.

for i in 0..<filteredObjects.count {
filteredObjects[i].score = scoreDict[$0.id.uuidString.lowercased()]
}

Also note that you only need to access the dictionary once. If it's nil, the key doesn't exist.

var filteredObjects = [Object]()
for i in 0..<objects.count {
if let score = scoreDict[$0.id.uuidString.lowercased()] {
objects[i].score = score
filteredObjects.append(objects[i])
}
}


Related Topics



Leave a reply



Submit