Reputation: 514
I have 2 arrays. Inside the first array I have a namelist that I want to remove from second array.
First array is simply array of strings:
var arrayNames = ["apple", "apricot", "cucumber"]
Second array is an array of custom structs
:
struct fruitsData {
var name: String?
}
var secondArray = [fruitsData(name: "apple"),fruitsData(name: "apricot"), fruitsData(name: "mango"), fruitsData(name: "grapes"), fruitsData(name: "tomato"), fruitsData(name: "lichi"), fruitsData(name: "cucumber"), fruitsData(name: "brinjal")]
So how could I get the array which contains this data only:
var finalData = [fruitsData(name: "mango"), fruitsData(name: "grapes"), fruitsData(name: "tomato"), fruitsData(name: "lichi"), fruitsData(name: "brinjal")]
which does not include any name from arrayNames
?
Upvotes: 1
Views: 1054
Reputation: 73176
The natural approach when wanting to construct a subset array from a given array and some predicate is using filter
. Since name
of the FruitsData
struct is an Optional
, you'll need to (attempt to) unwrap it prior to comparing it to the non-Optional
names in the arrayNames
list, e.g. using the map(_:)
method of Optional
along with optional chaining for handling nil
-valued name
cases.
E.g.:
// example setup
struct FruitsData {
var name: String?
}
let arrayNames = ["apple", "apricot", "cucumber"]
let secondArray = [
FruitsData(name: "apple"), FruitsData(name: "apricot"),
FruitsData(name: "mango"), FruitsData(name: "grapes"),
FruitsData(name: "tomato"), FruitsData(name: "lichi"),
FruitsData(name: "cucumber"), FruitsData(name: "brinjal")
]
// filter 'secondArray' based on the non-existance of an
// associated fruit name in the 'arrayNames' list
let finalData = secondArray.filter {
$0.name.map { fruitName in !arrayNames.contains(fruitName) } ?? true
}
Since String
conforms to Hashable
, you might also want to consider letting the list of fruit names to be excluded (arrayNames
) be a Set
rather than an Array
, as the former will allow O(1)
lookup when applying contains { ... }
to it. E.g.:
let removeNames = Set(arrayNames)
let finalData = secondArray.filter {
$0.name.map { fruitName in !removeNames.contains(fruitName) } ?? true
} /* ^^^^^^^^- O(1) lookup */
If you'd also like to filter out FruitsData
instances in secondArray
that have nil
valued name
properties, you can simply with the ... ?? true
predicate part above to ... ?? false
: the filter
operation will then filter out all FruitsData
instances whose name
property is either nil
or present in arrayNames
.
// ... filter out also FruitsData instances with 'nil' valued 'name'
let removeNames = Set(arrayNames)
let finalData = secondArray.filter {
$0.name.map { fruitName in !removeNames.contains(fruitName) } ?? false
}
Upvotes: 0
Reputation: 17534
If the name is NOT expected to be an empty string, you can use
let arrayNames = ["apple"]
struct fruitsData {
var name: String?
}
var secondArray = [fruitsData(name: "apple"),fruitsData(name: "apricot"), fruitsData()]
// [__lldb_expr_98.fruitsData(name: Optional("apple"))]
let flt1 = secondArray.filter { arrayNames.contains($0.name ?? "") }
// [__lldb_expr_87.fruitsData(name: Optional("apricot")), __lldb_expr_87.fruitsData(name: nil)]
let flt2 = secondArray.filter { !arrayNames.contains($0.name ?? "") }
Upvotes: 0
Reputation: 6795
Your finalData
from secondArray
excluding arrayNames
can be achieved here . .
var finalData = secondArray.filter { !arrayNames.contains($0.name!)}
Upvotes: 1
Reputation: 4795
There are a couple of ways to do this:
the best way is using a filter
method:
var arrayNames = ["apple", "apricot", "cucumber"]
var secondArray = [fruitsData(name: "apple"),fruitsData(name: "apricot"), fruitsData(name: "mango"), fruitsData(name: "grapes"), fruitsData(name: "tomato"), fruitsData(name: "lichi"), fruitsData(name: "cucumber"), fruitsData(name: "brinjal")]
secondArray = secondArray.filter({$0.name != nil && !arrayNames.contains($0.name!)})
alternatively, if you want to sacrifice efficiency for the sake of readability, you can use a for-in
loop alongside a helper Array:
var arrayNames = ["apple", "apricot", "cucumber"]
var secondArray = [fruitsData(name: "apple"),fruitsData(name: "apricot"), fruitsData(name: "mango"), fruitsData(name: "grapes"), fruitsData(name: "tomato"), fruitsData(name: "lichi"), fruitsData(name: "cucumber"), fruitsData(name: "brinjal")]
var helperArray = [fruitsData]()
for fruit in secondArray {
if fruit.name != nil && !arrayNames.contains(fruit.name!){
helperArray.append(fruit)
}
}
secondArray = helperArray
The above will erase every element from secondArray
whose name is contained by arrayNames
. You should familiarise yourself with Map, Filter and Reduce.
Upvotes: 1
Reputation: 1374
I am on the phone so I can't check it, but this should do the trick
secondArray.filter { !firstArray.contains($0.name) }
Upvotes: 0