Check if array contains element in Swift 4 - arrays

I am trying to check if array categories contain number 1 as Int since categories = [Int]() for example categories = {1, 2, 3, 4, 5}
I have tried the below code which gives me error Binary operator '==' cannot be applied to operands of type 'Any' and 'Int'
if categories.contains (where: {$0 == 1}) {
// 1 is found
}
also tried it without the where and brackets as below which gives me the same error
if categories.contains { $0 == 1 } {
// 1 is found
}
I tried using just the element as below which gives me error Missing argument label 'where:' in call
if categories.contains(1) {
// 1 is found
}
How can I do that?

It seems like your category array is of type Any
Ways to fix it
You can declare your array as an Int array
var categories: [Int]
OR
You can change the following piece of code
if categories.contains { $0 == 1 } {
// 1 is found
}
to
if categories.contains { ($0 as! Int) == 1 } {
// 1 is found
}
Note: This method might cause your app to crash if your category array has an element other than of type Int

it is working See my output in PlayGround
Code used:
var categories : [Int] = [0,1,2,3,4,5,6,7,8,9]
if categories.contains(5)
{
print("Yes it contains")
}
else
{
print("it do not")
}
and also This condition is working
if categories.contains (where: {$0 == 1}) {
print("yes")
}
see your Array Declaration I think there is main Issue
Declaration 1 :
var categories = [Int]()
categories = [0,1,2,3,4,5,6,7,8,9]
Declaration 2 :
var categories : [Int] = [0,1,2,3,4,5,6,7,8,9]

Regarding error message
Binary operator '==' cannot be applied to operands of type 'Any' and 'Int'
Your array is not an Int array instead it contains Any so it needs typecasting before comparision. Declaration of array is also wrong use [] instead of {}. And typecast object as an int ($0 as! Int) == 1 (I'm using force casting here because I know its an Int array).
There are many ways to check if array contains any element.
1> Just try to get the index of element with guard if index is nil means array doesn't contain the element. Although you didn't declare array in right way still I'm considering it a valid array.
let categories: [Int] = [1, 2, 3, 4, 5]
guard categories.index(of: 1) != nil else {
print("Doesn't Contain")
return
}
print("Contains")
2> Use contains method
if (categories.contains(1)) {
print("Contains")
}
else {
print("Doesn't Contain")
}
3> Not Recommended for this case But still you can get this
let result = categories.filter({$0 == 1})
if result.count == 0 {
print("Doesn't Contain")
}
else {
print("Contains")
}
filter returns an array of element which matches with condition. So that if there are multiple 1 in array so it will give you an array of all elements. And $0 describes the object while enumerating the array.
4> Not Recommended for this case
let contains = categories.contains(where: {$0 == 1})
if contains {
print("Contains")
}
else {
print("Doesn't Contain")
}

Thanks to your comments made me check the declaration of the array and the problem was that was declared as [Any] after I get it's value from the UserDefaults. I have checked and found the solution on How do I save an Int array in Swift using NSUserDefaults?
// old declaration
let categories = userDefaults.array(forKey:"categories") ?? [Int]()
// new correct declaration
var categories = [Int]()
if let temp = userDefaults.array(forKey:"categories") as? [Int] {
categories = temp
}

Related

Swift - Smart way to cycle through an Array of Array [[Int]]

I use an Array of Array [[Int]] storing coordinates in a map.
I for example want to replace all "2" with "1".
For this I created 2 for loops which define the array space and check for the content.
This is not very flexible and only works with arrays of the defined size.
private func remove2fromArray(currentArray: [[Int]]) -> [[Int]] {
var newArray : [[Int]] = currentArray
for section in 0...14 {
for row in 0...19 {
if newArray[section][row] == 2
{ newArray[section][row] = 1 }
}
}
return newArray
}
Is there a way to just scan through the content of the array to replace the numbers?
e.g.
currentArray.findAndReplace(find:2, replace: 1) or similar, that works with [[Int]]?
You can do it this way:
let result = array.map { subarray in
subarray.map { integer -> Int in
if integer == 2 {
return 1
} else {
return integer
}
}
}
Even shorter:
let result = array.map {
$0.map { integer in
return integer == 2 ? 1 : integer
}
}
And a one-liner:
let result = array.map { $0.map { $0 == 2 ? 1 : $0 } }
I'll try to explain what's happening here in simple words: What map does is that it goes through the array elements one by one and applies a function on the element.
In our example, the first map iterates over the outer array elements, so $0 here refers to the inner arrays (one after one).
The second map iterates over the inner arrays' elements. So $0 in the inner map refers to the each element of the inner arrays' elements.

N-Dimensional array swift

Is there any way to have an n dimensional array in swift? I would like to be able to make a function that creates an array with n dimensions but I cannot figure out how.
Basically something like this:
func ndarray <T> (dimensions: Int...) -> [[T]] { // What do I tell it I return?
var out
for d in dimensions {
out = Array<T>(repeating: out, count: d)
}
return out
}
The above code does not work for obvios reasons but, I think it points out the main problems I am having:
How do I define a return type
How do I actually create the array
Once created how do I traverse and populate the array
Here is the implementation of an N-Dimensional Array. It uses a normal array internally for storage and converts the multi-dimensional indices into a single index for the internal array.
struct NDimArray<T> {
let dimensions: [Int]
var data: [T]
init(dimensions: Int..., initialValue: T) {
self.dimensions = dimensions
data = Array(repeating: initialValue, count: dimensions.reduce(1, *))
}
init(dimensions: Int..., initUsing initializer: () -> T) {
self.dimensions = dimensions
data = (0 ..< dimensions.reduce(1, *)).map { _ in initializer() }
}
// Compute index into data from indices
private func computeIndex(_ indices: [Int]) -> Int {
guard indices.count == dimensions.count else { fatalError("Wrong number of indices: got \(indices.count), expected \(dimensions.count)") }
zip(dimensions, indices).forEach { dim, idx in
guard (0 ..< dim) ~= idx else { fatalError("Index out of range") }
}
var idx = indices
var dims = dimensions
var product = 1
var total = idx.removeLast()
while !idx.isEmpty {
product *= dims.removeLast()
total += (idx.removeLast() * product)
}
return total
}
subscript(_ indices: Int...) -> T {
get {
return data[computeIndex(indices)]
}
set {
data[computeIndex(indices)] = newValue
}
}
}
Example:
// Create a 3 x 4 x 5 array of String with initial value ""
var arr = NDimArray<String>(dimensions: 3, 4, 5, initialValue: "")
for x in 0 ..< 3 {
for y in 0 ..< 4 {
for z in 0 ..< 5 {
// Encode indices in the string
arr[x, y, z] = "(\(x),\(y),\(z))"
}
}
}
// Show internal storage of data
print(arr.data)
["(0,0,0)", "(0,0,1)", "(0,0,2)", "(0,0,3)", "(0,0,4)", "(0,1,0)", "(0,1,1)", "(0,1,2)", "(0,1,3)", "(0,1,4)", "(0,2,0)", "(0,2,1)", "(0,2,2)", "(0,2,3)", "(0,2,4)", "(0,3,0)", "(0,3,1)", "(0,3,2)", "(0,3,3)", "(0,3,4)", "(1,0,0)", "(1,0,1)", "(1,0,2)", "(1,0,3)", "(1,0,4)", "(1,1,0)", "(1,1,1)", "(1,1,2)", "(1,1,3)", "(1,1,4)", "(1,2,0)", "(1,2,1)", "(1,2,2)", "(1,2,3)", "(1,2,4)", "(1,3,0)", "(1,3,1)", "(1,3,2)", "(1,3,3)", "(1,3,4)", "(2,0,0)", "(2,0,1)", "(2,0,2)", "(2,0,3)", "(2,0,4)", "(2,1,0)", "(2,1,1)", "(2,1,2)", "(2,1,3)", "(2,1,4)", "(2,2,0)", "(2,2,1)", "(2,2,2)", "(2,2,3)", "(2,2,4)", "(2,3,0)", "(2,3,1)", "(2,3,2)", "(2,3,3)", "(2,3,4)"]
print(arr[2, 2, 2]) // "(2,2,2)"
print(arr[3, 0, 0]) // Fatal error: Index out of range
print(arr[0, 4, 0]) // Fatal error: Index out of range
print(arr[2]) // Fatal error: Wrong number of indices: got 1, expected 3
Initializing an Array with a Reference Type
As #DuncanC noted in the comments, you have to be careful when initializing an array with a value which is a reference type, because the array will be filled with references to the object and modifying the object at any index will modify all of them.
To solve this, I added a second initializer:
init(dimensions: Int..., initUsing initializer: () -> T)
which takes a closure () -> T which can be used to create a new object for each element of the array.
For example:
class Person {
var name = ""
}
// Pass a closure which creates a `Person` instance to fill the array
// with 25 person objects
let arr = NDimArray(dimensions: 5, 5, initUsing: { Person() })
arr[3, 3].name = "Fred"
arr[2, 2].name = "Wilma"
print(arr[3, 3].name, arr[2, 2].name)
Fred Wilma
Nope, it's not possible. Array dimensions is something that needs to be determined at compile time, while the argument you want to pass to the initializer will not be known until runtime. If you really want to achieve something like this, then you'll need to move the array indexing from compile time to runtime, e.g. by accessing the array via an array of indexes. Still you don't have compile validation, since the array length can at runtime to not match the dimensions of the array.
This problem is similar to the one that attempts to convert a tuple to an array.

Compare Optional Bool variable doesn't work

I have to create a 2D Array of Optional Bool type and compare the value inside it but I can't.
The first time I try to declare in this way:
var Answ = [[Bool?]] ()
var Page = 0
for i in 0...4
{
if Answ[Page][i] == true
{...}
else if Answ[Page][I] == false
{...}
else
{...}
}
...
but when I launch the program, it says:
index out of range
when Xcode compares the Answ[Page][i] with the value true.
So, I try to modify the code and declare the array in this way:
var Answ = Array (repeating: Array (repeating: Bool?.self , count: 5), count: 40)
var Page = 0
for i in 0...4
{
if Answ[Page][i] == true
{...}
else if Answ[Page][I] == false
{...}
else
{...}
}
...
but at the same point, (if Answ[Page][i] == true) throws this error:
Binary operator '==' cannot be applied to operands of type 'Bool?.Type' (aka 'optional.Type') and 'Bool'"
Moreover, in other points of the code where I try to set a value of the array as true/false (Answ[Page][2] = true), Xcode says this:
cannot assign value of type 'Bool' to type 'Bool?.Type' (Aka'Optional.Type')
Can someone help me, please? Thank you in advance.
I found this topic:
Checking the value of an Optional Bool
but it didn't help me much.
You can compare optional bools as in the Q&A that you linked to. The problem is that
var Answ = Array (repeating: Array (repeating: Bool?.self , count: 5), count: 40)
creates a (nested) array of Bool?.self, which is the type of an optional bool, not a value of that type.
What you want is a (nested) array of Bool? values, initialized to nil:
var answers: [[Bool?]] = Array(repeating: Array(repeating: nil , count: 5), count: 40)
or alternatively:
var answers = Array(repeating: Array(repeating: Bool?.none , count: 5), count: 40)
You should provide a fallback value with ??.
By the way, you don't need to write == false or == true, it's redundant.
if Answ[Page][i] ?? false {
  [...]
}
There are several issues with your code. First of all, don't use manual indexing in a for loop, rather use for ... in to have the indexes automatically handled for you. Secondly, a better solution for handling optional booleans is to safely unwrap the value using optional binding and then check the non-optional value. You also don't need to write if bool == true, if bool has the same meaning.
Also please make sure you conform to the Swift naming convention, which is lower-camelCase for variable names.
var answ = [[Bool?]] ()
var page = 0
for ans in answ[page]{
if let unwrappedAns = ans {
if unwrappedAns {
// answ[page][i] = true
} else {
}
} else {
//answ[page][i] = ans is nil
}
}
If you actually want to iterate through the whole array of arrays, this is one safe way for doing so:
for page in answ {
for ans in page {
//here ans = Answ[Page][i] when compared to the code in your question
if let unwrappedAns = ans {
if unwrappedAns {
} else {
}
} else {
//ans is nil
}
}
}

Cannot subscript a value of type Array<Element> with index of type CountableRange<Int>

Error:
Cannot subscript a value of type Array with index of type CountableRange
I want to find say some top elements from any array/Sequence.
extension Array {
func top(max:Int) -> Array {
guard self.count > max else {
return self
}
let last = max - 1
return self[0..<max]
}
}
This functionality already exists in the standard library, in the form of Array.prefix(_:)
But to address the issue in this code:
The error here is actually not actually that you can't subscript a value of type Array with index of type CountableRange, but rather, that you can't do so to produce a result of type Array.
Subscripting an Array by a range yields an ArraySlice, not an Array. Thus, your code would have to be:
extension Array {
func first(_ maxLength: Int) -> ArraySlice<Element> {
return self[0 ..< Swift.min(maxLength, self.count)]
}
}
Thanks #Leo and #Alexander for your prompt replies :)
extension Array {
func first(max: Int) -> Array {
return Array(prefix(max))
}
}

How to Remove Every Other Element in an Array in Swift?

So say I have an array:
var stringArray = ["a","b","c","d","e","f","g","h","i","j"]
Now, how do I delete "a", "c", "e", "g", and "i" (all the even number indexes from the array)?
Thanks!
Instead of using C-style for-loops (which are set to be deprecated in an upcoming version of Swift), you could accomplish this using strides:
var result = [String]()
for i in stride(from: 1, through: stringArray.count - 1, by: 2) {
result.append(stringArray[i])
}
Or for an even more functional solution,
let result = stride(from: 1, to: stringArray.count - 1, by: 2).map { stringArray[$0] }
Traditional
var filteredArray = []
for var i = 1; i < stringArray.count; i = i + 2 {
filteredArray.append(stringArray[i])
}
Functional alternative
var result = stringArray.enumerate().filter({ index, _ in
index % 2 != 0
}).map { $0.1 }
enumerate takes a array of elements and returns an array of tuples where each tuple is an index-array pair (e.g. (.0 3, .1 "d")). We then remove the elements that are odd using the modulus operator. Finally, we convert the tuple array back to a normal array using map. HTH
There are a bunch of different ways to accomplish this, but here are a couple that I found interesting:
Using flatMap() on indices:
let result: [String] = stringArray.indices.flatMap {
if $0 % 2 != 0 { return stringArray[$0] }
else { return nil }
}
Note: result needs to be defined as a [String] otherwise the compiler doesn't know which version of flatMap() to use.
Or, if you want to modify the original array in place:
stringArray.indices.reverse().forEach {
if $0 % 2 == 0 { stringArray.removeAtIndex($0) }
}
In this case you have to call reverse() on indices first so that they're enumerated in reverse order. Otherwise by the time you get to the end of the array you'll be attempting to remove an index that doesn't exist anymore.
Swift 4.2
A function accepting generics and producing reduced result
func stripElements<T>(in array:[T]) -> [T] {
return array.enumerated().filter { (arg0) -> Bool in
let (offset, _) = arg0
return offset % 2 != 0
}.map { $0.element }
}

Resources