IndexSet is a collection of increasing integers, therefore you can
map each index to the corresponding array element:
let array = ["sun", "moon", "star", "meteor"]
let indexSet: IndexSet = [2, 3]
let result = indexSet.map { array[$0] } // Magic happening here!
print(result) // ["star", "meteor"]
This assumes that all indices are valid for the given array. If that is not guaranteed then you can filter the indices (as @dfri correctly remarked):
let result = indexSet.filteredIndexSet { $0 < array.count }.map { array[$0] }
Answer from Martin R on Stack OverflowIndexSet is a collection of increasing integers, therefore you can
map each index to the corresponding array element:
let array = ["sun", "moon", "star", "meteor"]
let indexSet: IndexSet = [2, 3]
let result = indexSet.map { array[$0] } // Magic happening here!
print(result) // ["star", "meteor"]
This assumes that all indices are valid for the given array. If that is not guaranteed then you can filter the indices (as @dfri correctly remarked):
let result = indexSet.filteredIndexSet { $0 < array.count }.map { array[$0] }
You can use enumerated, filter and map like this
let result = array
.enumerated()
.filter { indexSet.contains($0.offset) }
.map { $0.element }
You can filter the indices of the array directly, it avoids the extra mapping.
let items = ["A", "B", "A", "C", "A", "D"]
let filteredIndices = items.indices.filter {items[$0] == "A"}
or as Array extension:
extension Array where Element: Equatable {
func whatFunction(_ value : Element) -> [Int] {
return self.indices.filter {self[$0] == value}
}
}
items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]
or still more generic
extension Collection where Element: Equatable {
func whatFunction(_ value : Element) -> [Index] {
return self.indices.filter {self[$0] == value}
}
}
You can create your own extension for arrays.
extension Array where Element: Equatable {
func indexes(of element: Element) -> [Int] {
return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
}
}
You can simply call it like this
items.indexes(of: "A") // [0, 2, 4]
items.indexes(of: "B") // [1]
Videos
Can you filter an array in Swift?
How do you apply a filter on an array of objects in Swift?
How does the filter() function work in Swift?
Assuming that
- the given indices are in increasing order, and
- all indices are valid for the array (i.e. less than the number of elements),
then a simple map operation would work:
let indexes = [2, 4, 7]
let myArray = ["a", "b", "c", "d", "e", "f", "g", "h"]
let filtered = indexes.map { myArray[$0] }
print(filtered) //["c", "e", "h"]
Remark: In earlier Swift releases, there was a PermutationGenerator
exactly for this purpose:
let filtered = Array(PermutationGenerator(elements: myArray, indices: indexes))
print(filtered) //["c", "e", "h"]
However, this has been deprecated in Swift 2.2 and will be removed in Swift 3. I haven't seen a Swift 3 replacement yet.
you can try, although that's far away from efficient. But that's what you get if you insist on using filter
let myArray = ["a", "b", "c", "d", "e"]
var indexes = [1, 3]
myArray.filter { (vowel) -> Bool in
if let index = myArray.indexOf(vowel) {
return indexes.contains(index)
}
return false
}
I have an array of Match objects [Match] with a string property of matchID. I also have an array of strings.
I would like to remove the Match object where matchID equals any string in the array.
I currently have:
var matches = [Match]
var matchIDsToDelete = [String]
for match in matches {
for id in matchIDsToDelete {
if match.matchID == id {
// remove that item from array
}
}
}My concern is removing the object from the array as I'm enumerating. I believe there will be consequences. Any suggestions? I would also love a functional solution as I'm currently reading more about functional programming.
Thanks!
If I read the question correctly, you want to find the index of the array who's first element matches a search pattern. The following demonstrates how to do that:
var receivedList = [["Name1","Apple","Fresh"],["Name2","Orange","Rotten"],["Name3","Pear","Fresh"],["Name4","Grape","Rotten"]]
var searchText = "Name2"
let index = receivedList.index { $0[0] == searchText }
print(index)
The following will filter your list to only those whose first element contains the search text:
let matches = receivedList.filter { $0[0].contains(searchText) }
If you want the indexes that match, then you can use:
let matches = receivedList
.enumerated()
.filter { $0.1[0].contains(searchText) }
.map { $0.0 }
var receivedList = [["Name1","Apple","Fresh"],["Name2","Orange","Rotten"],["Name3","Pear","Fresh"],["Name4","Grape","Rotten"]]
func filter(keyword: String)-> [[String]] {
return receivedList.filter({ (stringArr) -> Bool in
for value in stringArr {
if value.lowercased().contains(keyword.lowercased()) {
return true
}
}
return false
})
}
var filtered = filter(keyword: searchBar.text ?? "") //Here you will get filtered values
The way you are doing it is not correct, you are altering an array while looping through it. When you remove an object from the array, the array count changes but the loop still run using the previously calculated array.count value.
There is a much simpler way of doing this, you just need to combine filter and contains functions together for achieving this:
func filterArray( _ x: [Int], _ nums: Int...) -> [Int]
{
let filteredArray = x.filter({ !nums.contains($0)})
return filteredArray
}
once you remove one element from array its size change, but your loop is still going till previous count that is causing the issue try taking different array to go through the loop and for storing the result and you don't need to find the index its already there, value of 'i' is the index of the element.
One approach is to update your filter to see if any value in pets is in the petArr array:
users = users.filter { $0.pets.contains(where: { petArr.contains($0) }) }
The first $0 is from the filter and it represents each User.
The second $0 is from the first contains and it represents each pet within the pets array of the current User.
If elements inside the internal array are Equatable you can just write:
array1 = array1.filter{ $0.arrayInsideOfArray1 == array2 }
If they are not, you can make them, by adopting Equatable protocol and implementing:
func ==(lhs: YourType, rhs: YourType) -> Bool
contains() checks if a sequence contains a given element, e.g.
if a String contains a given Character.
If your intention is to find all books where the name contains the substring "rt", then you can use rangeOfString():
var arr = englishBooks.filter {
$0.nameOfBook.rangeOfString("rt") != nil
}
or for case-insensitive comparison:
var arr = englishBooks.filter {
$0.nameOfBook.rangeOfString("rt", options: .CaseInsensitiveSearch) != nil
}
As of Swift 2, you can use
nameOfBook.containsString("rt") // or
nameOfBook.localizedCaseInsensitiveContainsString("rt")
and in Swift 3 this is
nameOfBook.contains("rt") // or
nameOfBook.localizedStandardContains("rt") // or
nameOfBook.range(of: "rt", options: .caseInsensitive) != nil
Sorry this is an old thread. Change you code slightly to properly init your variable 'nameOfBook'.
class book{
var nameOfBook: String!
init(name: String) {
nameOfBook = name
}
}
Then we can create an array of books.
var englishBooks = [book(name: "Big Nose"), book(name: "English Future
Prime Minister"), book(name: "Phenomenon")]
The array's 'filter' function takes one argument and some logics, 'contains' function can take a simplest form of a string you are searching for.
let list1 = englishBooks.filter { (name) -> Bool in
name.contains("English")
}
You can then print out list1 like so:
let list2 = arr1.map({ (book) -> String in
return book.nameOfBook
})
print(list2)
// print ["English Future Prime Minister"]
Above two snippets can be written short hand like so:
let list3 = englishBooks.filter{ ($0.nameOfBook.contains("English")) }
print(list3.map({"\($0.nameOfBook!)"}))
This is what I have working in a playground, any reason why this is no good?
class Book {
var author = String()
init(author:String){
self.author = author
}
}
var allBooks: [Book] = []
allBooks.append(Book(author: "John Smith"))
allBooks.append(Book(author: "Arthur Price"))
allBooks.append(Book(author: "David Jones"))
allBooks.append(Book(author: "Somebody Else"))
let authors = ["Arthur Price", "David Jones"]
let filteredBooks = allBooks.filter({authors.contains($0.author)})
filteredBooks // [{author "Arthur Price"}, {author "David Jones"}]
You could also use something like
let authorsAndBooks = authors.map {
(authorName) -> (String, [Book])
in (authorName,
allBooks.filter({ $0.author == authorName })
)
}
This will array of tuples with the first element being the author name and the second element an array of his books, in case an author wrote more than one book.