How to remove item in Array? [duplicate] - ios

This question already has answers here:
RemoveAtIndex crash from swift array
(5 answers)
Closed 6 years ago.
I am coding with Swift, and confuse with one problem.
I encountered Index out of Range Error when I am trying to remove one item from array during the array's enumeration.
Here is my error codes:
var array :[Int] = [0,1,2,3,4,5]
for (index, number) in array.enumerate() {
if array[index] == 2 {
array.removeAtIndex(index) // Fatal error: Index out of range
}
}
Does that means array.enumerate() not be called during each for loop?
I have to change my codes like that:
for number in array {
if number == 2 || number == 5 {
array.removeAtIndex(array.indexOf(number)!)
}
}
Or
var index = 0
repeat {
if array[index] == 2 || array[index] == 4 {
array.removeAtIndex(index)
}
index += 1
} while(index < array.count)

You are removing item at the same time when you are enumerating same array. Use filter instead:
var array: [Int] = [0,1,2,3,4,5]
array = array.filter{$0 != 2}
or, for multiple values, use Set:
let unwantedValues: Set<Int> = [2, 4, 5]
array = array.filter{!unwantedValues.contains($0)}
Same in one line:
array = array.filter{!Set([2, 4, 5]).contains($0)}

Related

Function and array of strings using swift [duplicate]

This question already has answers here:
How to sort array of strings by length in reverse/descending order in Swift?
(2 answers)
Closed last year.
Good day everyone I want to create a function that takes an array of strings and return an array, sorted from shortest to longest but I'm getting a terminated by signal 4 error. I'm using an online swift compiler on my windows laptop if that somehow matters.
here's the code I wrote:
var siliconvalley = ["Google", "Apple", "Microsoft"]
var elementamount: Int = siliconvalley.count
var newarray: [String] = [] //new array created to store the newly sorted array
var a = siliconvalley[0].count // this variable was created to count the letters of the first string in the array
var temporary: String = "" // this was created to store the largest string so that I can use it to append the new array
func longestelement () -> [String] {
repeat {
if siliconvalley[1].count > a {
print (siliconvalley[1])
temporary = siliconvalley[1]
siliconvalley.remove(at:1)
}
else if siliconvalley[2].count > a {
print (siliconvalley[2])
temporary = siliconvalley[2]
siliconvalley.remove(at:2)
}
else {
print (siliconvalley[0])
temporary = siliconvalley[0]
siliconvalley.remove(at:0)
}
newarray.append(temporary)
elementamount = elementamount - 1
} while elementamount > 0
return newarray
}
print (longestelement())
You know swift has built-in sorting? You can do:
siliconvalley.sorted(by: {$0.count < $1.count})
and then if you just want the longest use .last
here's the issue:
while elementamount > 0
Consider rechecking the code for possible illogical loop termination condition.
P.S: elementamount is always greater than 0.

Remove matching entry from an array

I have 2 sections in my tableview. Section 0 has data from an array and section 1 has data from an api. Now I want to check if the data from section 0 has a matching data to that of section 1 then I want to remove that particular entry from section 1. Not sure how to do that…
I have 2 arrays which populate data in each of the sections:
filteredSelectedProductList —> Section 0
productsList —> Section 1
This is the code I have:
if self.filteredSelectedProductList.isEmpty == false {
for prod in self.filteredSelectedProductList { //section 0
for filtProd in productsList { //section 1
if prod.productId == filtProd.productId {
//Here I want to remove the matching entry from productsList array. How can I do that..?
}
}
}
}
You can use filter where not contains,
something like this should work,
var arr1 = [1,3,4,5,6] // array 1 section 0
var arr2 = [2,34,5,6] // array 2 section 1
print(arr2.filter{!arr1.contains($0)}) // [2,34]
In your case you are using custom model, you can confirm to Equatable and do the following with it, then you can simple use it as i showed you above.
struct MyCustomObject {
var id: Int // some unique id you can compare things to
}
extension MyCustomObject: Equatable {
static func == (lhs: MyCustomObject, rhs: MyCustomObject) -> Bool {
return lhs.id == rhs.id
}
}
Usage :
var arra1: [MyCustomObject] = [] // section 0
var arra2: [MyCustomObject] = [] // section 1
print(arra2.filter{!arra1.contains($0)})
Swift 4.1
You can do by this way, You just have to put your array instead of this
var array1 = ["45","34","67"] //section 0
var array2 = ["45", "23"] // section 1
array2.removeAll(where: { array1.contains($0) }) // finalArray = ["23"]
You can use removeAll:
productsList.removeAll(where: { filteredSelectedProductList.contains($0) })
To use the contains, your models must conform to Equatable, otherwise you should do like this:
productsList.removeAll(where: { item in filteredSelectedProductList.contains(where: { $0.productId == item.productId }) })
Array.contains is an O(n) operation. Meaning that each element in the first array, you may have to search all of the second array. Resulting in O(m * n), m and n being the counts of the arrays, which is not efficient.
A better way would be to:
build a dictionary of the occurrences of elements in the first array,
then loop through the second array,
Append the elements in the second array that don't belong to the first one.
Here a function that does the above steps with a time complexity of O(m + n):
func intersect<T: Hashable>(_ a1: [T], with a2: [T]) -> [T] {
var result = [T]()
result.reserveCapacity(a2.count)
var dict1: [T: Int] = [T: Int].init(minimumCapacity: a1.count)
for x in a1 {
dict1[x, default: 0] += 1
}
for y in a2 {
if dict1[y] == nil || dict1[y] == 0 {
result.append(y)
} else {
dict1[y]! -= 1
}
}
return result
}
Note that the elements of the arrays have to conform to Hashable in order to use a dictionary. If an element occurs in the second array more than in the first, the extra duplicates are the ones kept. Which is not handled in all other answers
Here are some use cases :
let array1 = [1, 2, 3, 4, 5, 6]
let array2 = [1, 2, 2, 4, 7, 6]
intersect(array1, with: array2) //[2, 7]
struct MyStruct: Hashable { var id: Int }
let array3 = [MyStruct(id: 0), MyStruct(id: 2), MyStruct(id: 3)]
let array4 = [MyStruct(id: 1), MyStruct(id: 2), MyStruct(id: 2)]
intersect(array3, with: array4) //[{id 1}, {id 2}]

Sort an array on three variables [duplicate]

This question already has answers here:
Swift - Sort array of objects with multiple criteria
(8 answers)
Closed 5 years ago.
I have an array with playing cards. I would like to sort these on value, color and playability.
I have 4 colors; 1, 2, 3, 4.
I have 3 playability options; 1, 2, 3.
I have 5 values; 1, 2, 3, 4, 5.
I am able to sort the array on color and value. So if the color is the same, the array is sorted on value.
example color-value pairs:
1-2, 1-4, 1-5, 2-2, 3-1, 3-2, 3-5
Code is,
playerCards.sort {
if $0.colorSorter == $1.colorSorter {
return $0.value < $1.value
}
return $0.colorSorter < $1.colorSorter
}
How do I add the third paramater to sort on playability additionally?
What I would like to see (playability-color-value triplets):
1-1-2, 1-1-4, 1-2-2, 1-3-1, 2-1-5, 2-3-1, 2-3-2, 3-3-5
1: sort on playability
2: sort on color
3: sort on value.
Thanks!
Assuming this is your struct
struct Card {
let color:Int
let value:Int
let playability:Int
}
and this is your array
let cards:[Card] = ...
You can sort cards by
playability
color
value
writing
let sorted = cards.sorted { (left, right) -> Bool in
guard left.playability == right.playability else { return left.playability < right.playability }
guard left.color == right.color else { return left.color < right.color }
return left.value < right.value
}

'didSet' certain elements inside Arrays - Swift [duplicate]

This question already has an answer here:
Swift didSet get index of array
(1 answer)
Closed 5 years ago.
I have an array, with multiple values. I want to detect if one of those values is changed, something like this:
var array =
[
1,
2,
3,
4 { didSet{ print("Value Changed")}},
5,
6
]
Is that possible, in any way?
Thanks
Swift 3.0
You can do like below to Observer which index of array is changed.
var oldArray: [Int] = []
var array = [ 1,2,3,4,5,6] {
willSet {
// Set old array value for compare
oldArray = array
}
didSet {
let changedIndex = zip(array, oldArray).map{$0 != $1}.enumerated().filter{$1}.map{$0.0}
print("index: \(changedIndex)")
}
}
// Now change value of index 4 of array
array[4] = 10 //index: [4]

Best way to check if object is out of bounds in array

What is the best practice to check if an object exists (is within bounds) at a specific index in an Array?
It would be nice to have it as simple as this, but that is unfortunately not possible:
let testArray = ["A", "B", "C", "D"]
if let result = testArray[6] {
println("Result: \(result)")
}
else {
println("Result does not exist. Out of bounds.")
}
Will I have to check against the total count?
Thank you!
You could also make an extension to Array, so you will be able to check with if-let:
extension Array {
func at(index: Int) -> Element? {
if index < 0 || index > self.count - 1 {
return nil
}
return self[index]
}
}
let arr = [1, 2, 3]
if let value = arr.at(index: 2) {
print(value)
}
You can use the ~= operator in conjunction with the indices function, which is a shortcut for creating a range of the full index range of a container:
let a = [1,2,3]
let idx = 3 // one past the end
if indices(a) ~= idx {
println("within")
}
else {
println("without")
}
The one thing to note is this works with any kind of container that has a comparable index, not just ones like array that have integer indices. Thinking of indices as numbers is generally a good habit to get out of, since it helps you think more generally about algorithms on containers without these indices, such as strings or dictionaries:
let s = "abc"
let idx = s.endIndex
idx < count(s) // this won't compile
idx < s.startIndex // but this will
// and so will this
if indices(s) ~= idx {
println("within")
}
else {
println("without")
}
The more general your algorithms, the more chance you will be able to factor them out into generics and increase re-use.
#alkku has it but for simplicity and using the most underused syntactic form in all languages ?::
extension Array {
func atIndex(index: Int) -> T? {
return (0 <= index && index < self.count
? self[index]
: nil)
}
}
There is a new (neat) way to do it in Swift:
array.indices.contains(index)
Check if object index used should be greater or equal to zero and should be less total count of array like this :
//Here index is object you want for
if(index >= 0 && index < [yourArray count])
{
//inside of array
}
else
{
//out of bound
}
To check whether or not an index is inside the bounds of an array in swift you would use
if index < testArray.count {
//index is inside bounds
} else {
//index is outside bounds
}

Resources