How to get all tuples with specific value in swift - arrays

Say I have an array of tuples like this:
var countryData = [
(country:"Australia", item:"GDP", Year:"2019", dataValue:"1.434 trillion"),
(country:"Australia", item:"CPI", Year:"2019", dataValue:"6401.0"),
(country:"Australia", item:"Inflation", Year:"2019", dataValue:"1.61%"),
(country:"Brazil", item:"GDP", Year:"2019", dataValue:"$1.868 trillion"),
...
(country:"Zimbabwe", item:"Inflation", Year:"2019", dataValue:"255.29%"),
]
I want to create an instance variable to get all the tuples containing "Australia". I'm assuming I have to use a for loop and contain function but my swift isn't that good and I can't get it to work. Or any suggestions if this isn't the best way to go about this is also appreciated.

You are right! You can use for loop for this. The other way is the filter operator
filter operator way gives you an ability to filter an array of any type by specific criteria.
let neededList = countryData.filter { $0.country == "Australia" }
For loop way
var result: [(country: String, item: String, Year: String, dataValue: String)] = []
for item in countryData {
if item.country == "Australia" {
result.append(item)
}
}
print(result)

Use the higher order filter method. Here's how:
let australiaData = countryData.filter { $0.country == "Australia" }

Related

Extracting elements from a array of dictionaries

I have a array of dictionaries. From here I want to extract individual elements
The following code is generating an array which has multiple dictionaries. From this I need to extract values which match a certain key.
Code used:
return array.filter{namePredicate.evaluate(with: $0)}
This looks like:
[["a":"1","b":"2","c":3],["a":"3","b":"4","c":5]]
From this I need to extract values for key "a" ie 1, 3. How do I go about this?
Use compactMap:
let aValues = filteredArray.compactMap { $0["a"] }
where filteredArray is the array returned from array.filter{namePredicate.evaluate(with: $0)}.
please informed that, the filter will return the same type as the array it self, the map will return the new type you mean to return. so if you want to get the different type with it self, you need to use map function.
and in map functions "map" will return the same number of elements as the array it self, the "compactMap" will remove the 'nil' value.
so if you make sure all the 'dict' in your array have the key you need to get, you can use map, or you can you use compactMap to avoid nil value in the result array
so you can use
let arr = [["a":"1","b":"2","c":3],["a":"3","b":"4","c":5]]
let test = arr.map{$0["a"] as? String}
let test2 = arr.compactMap{$0["a"] as? String}
If you need to do with for multiple keys, you can make a merged dictionary that maps all keys to arrays of all values. You lose the ordering of the values, so this will only work if it's not necessary.
func merge<Key, Value>(dicts: [[Key: Value]]) -> [Key: [Value]] {
return dicts.reduce(into: [:]) { accumalatorDict, dict in
accumalatorDict.merge(
dict.mapValues({ [$0] }),
uniquingKeysWith: { return $0 + $1 }
)
}
}
let dicts: [[String: Any]] = [
["a":"1","b":"2","c":3],
["a":"3","b":"4","c":5]
]
let mergedDicts = merge(dicts: dicts)
for (key, values) in mergedDicts {
print(key, values)
}
let allValuesForA = mergedDicts["a"]
print(allValuesForA) // => ["1", "3"]
try this
let arr = [["a":"1","b":"2","c":3],["a":"3","b":"4","c":5]]
let test = arr.map{$0["a"] as? String}

How to filter an array to correspond other array

I've two arrays:
var filteredTitles = [String]()
var filteredTypes = [String]()
I filter the first array as a part of using searchbar. The order of the elements might change completely. However, I can't filter the second array the same way I did the first one, because I don't want to take it in to count when searching. But I would like for the second array to be in the same order as the first one. So, to recap. How can I filter an array to match another one by indexes perfectly?
An example:
var filteredArray = ["One", "Two", "Three"]
//Sort the below array to ["1", "2", "3"], the order of the upper array
var toBeFilteredArray = ["2", "1", "3"]
WITHOUT using alphabetical or numerical order, as that won't do in this case.
EDIT:
TO Russell:
How do I sort the titles like this:
// When there is no text, filteredData is the same as the original data
// When user has entered text into the search box
// Use the filter method to iterate over all items in the data array
// For each item, return true if the item should be included and false if the
// item should NOT be included
searchActive = true
filteredData = searchText.isEmpty ? original : original.filter({(dataString: String) -> Bool in
// If dataItem matches the searchText, return true to include it
return dataString.range(of: searchText, options: .caseInsensitive) != nil
})
don't have two arrays - have a single array of a custom type, containing both variables that you need
Define your struct
struct MyCustomData
{
var dataTitle : String = ""
var dataType : String = ""
}
and then declare it
var dataArray : [MyCustomData] = []
populate it and sort it where required - I have populated in reverse order just so that we can see it being sorted
dataArray.append(MyCustomData(dataTitle: "Third", dataType: "3"))
dataArray.append(MyCustomData(dataTitle: "Second", dataType: "2"))
dataArray.append(MyCustomData(dataTitle: "First", dataType: "1"))
let filteredArray = dataArray.sorted {$0.dataTitle < $1.dataTitle}
for filteredElement in filteredArray
{
print("\(filteredElement.dataTitle), \(filteredElement.dataType)")
}
// or, to print a specific entry
print("\(filteredArray[0].dataTitle), \(filteredArray[0].dataType)")
An example of keeping two separate arrays in sync using zip:
let titles = ["title1", "title3", "title4", "title2"]
let types = ["typeA", "typeB", "typeC", "typeD"]
let zipped = zip(titles, types)
// prints [("title4", "typeC"), ("title2", "typeD")]
print(zipped.filter { Int(String($0.0.characters.last!))! % 2 == 0 })
You can use map on the filtered result to get back two separate filtered arrays for the titles and types.

How to arrange one dictionary array by ascending order and then reorder the other arrays?

I am trying to sort an dictionary (of type [String:[String]]) so that one key is in ascending order, once the key is sorted I would like to sort the other arrays too.
This is what I mean.
var dictionary = ["timeStamp":[String],"condition":[String]] //Dict to sort
dictionary["timeStamp"] = ["123","345","456","234"]
dictionary["condition"] = ["dry","wet","very wet","dry"]
dictionary["timeStamp"] = dictionary["timeStamp"]!.sort()
print("\(dictionary["timeStamp"]!)") //Returns["123","234","345","456"]
How would I be able to sort dictionary["condition"] to be ["dry","dry","wet","very wet"]?
I would make a simple struct so that your properties are associated and can be sorted together
struct condition {
var timeStamp: Int
var description: String
}
var conditionArray = [condition]()
conditionArray.append(condition(timeStamp: 123, description: "dry"))
conditionArray.append(condition(timeStamp: 345, description: "wet"))
conditionArray.append(condition(timeStamp: 456, description: "very wet"))
conditionArray.append(condition(timeStamp: 234, description: "dry"))
let sortedArray = conditionArray.sort() {return $0.timeStamp < $1.timeStamp}
The preferred way is give it a proper structure like #Russel Austin suggested in his answer. But you can also have some fun with Swift higher-order functions:
var dictionary = [
"timeStamp": ["123","345","456","234"],
"condition": ["dry","wet","very wet","dry"]
]
let sorted = Array(0..<dictionary["timeStamp"]!.count)
.map { (timeStamp: dictionary["timeStamp"]![$0], condition: dictionary["condition"]![$0]) }
.sort { $0.timeStamp < $1.timeStamp }
dictionary["timeStamp"] = sorted.map { $0.timeStamp }
dictionary["condition"] = sorted.map { $0.condition }
print(dictionary)
Array(0..<dictionary["timeStamp"]!.count) generate an array of ints, going 0, 1, 2, 3... up to the length of timeStamp
.map { ... } pulls data from the dictionary into tuples of timestamp and condition
.sort{ ... } sorts the array of tuples by the timestamp

Obtain a subset of tuple array in swift

I have a array of tuples like the following
var customProducts = [(productType: String, info:[String:AnyObject?])]
The parameter "productType" works like a "product category", like fruits, grains, beverage, etc.
The parameter "info" is a dictionary of nutritional information of the product.
I want to get a subset of the tuples array, based on the productType so I could obtain just the "info" dictionary for an specific productType. In C# I would try something like the following using Linq:
var fruits = customProducts.Where(q=>q.productType == "fruit").Select(q => q.info) as List<KeyValuePair<string, object>>;
How may I archive the same results using Swift (2.x)?
Thanks!
I think the Swift equivalent would be:
let fruits = customProducts.filter { $0.productType == "fruit" }.map { $0.info }
Here fruits is [[String : AnyObject?]], an array of dictionaries (an array of info, the same as your List<KeyValuePair<string, object>> if I'm not mistaken).
You can use the filter method
let beverageInfo = (customProducts.filter { $0.productType == "Beverage" }).first?.info
Now beverageInfo is [String : AnyObject?]?, an optional dictionary representing the info for "Beverage" tuple.
You should filter the array according to what type the product is
Eg
var customProducts = [(productType: String, info:[String:AnyObject?])]
let fruitProducts = customProducts.filter { product in
if product.productType == "fruit" {
return true
} else {
return false
}
}.map { $0.info }
Then you can use fruitProducts however you want.

How to filter object from array by value and using the value to omit another array or objects?

I have a array, which has the bunch of object, i would like to filter the object by 'name' value, again i would like to omit those object from another array of object using underscore.
I know that we can do using earch, but i am not getting the proper approach to do this both..
any one help me to do this?
example :
incoming array:
var incomingArray = [
{"name":"apple"},
{"name":"orange"},
{"name":"dog"},
{"name":"cat"},
{"name":"egle"}
];
filter keys:
var omit = ['orange' ,'dog'];
//i need to check whether 'orange' or 'dog' are exist, if so..
var filtered = _.filter(incomingArray, function(obj, i){
return obj.name === omit[i]['name'];//this is wrong i need to loop again how?
});
var anotherArray = [
{"name":"apple"},
{"name":"orange"},
{"name":"dog"},
{"name":"cat"},
{"name":"egle"}
]
return only the array without the omit like this:
var outgoingArray = [
{"name":"apple"},
{"name":"cat"},
{"name":"egle"} ]
how we could achieve this with proper approach?
demo
You were nearly there! Use indexOf to check that the name does not belong in the omit array:
var filtered = _.filter(incomingArray, function(obj) {
return omit.indexOf(obj.name) == -1;
});

Resources