Checking if an array contains a string - arrays

I'm trying to evaluate if an entered string partially matches any item in an array. When I use the following method in playgrounds it seems to work properly. However, when I use the exact same method in Xcode 9.0 beta 6 (9M214v) it doesn't return the correct answer.
func isValid(_ item: String) -> Bool {
let whitelist = ["https://apple.com","https://facebook.com","https://stackoverflow.com"]
return whitelist.contains(where: {$0 <= item ? true : false })
}
There's also anomalies like when I passed in "https://twitter.com" it'll return true. Am I nuts? And while I'm here, anyone have a different approach to solve this problem?

theres also anomalies like when I passed in "https://twitter.com"
it'll return true.
Whether the version of Swift is 3 or 4, based on your code snippet you should get the same true result! Why?
because the logic of contains(where:) of doing the comparison is related to the logic of the equality of the given elements, i,e you cannot use contains with array of non-equatable elements. To make it more clear:
"https://apple.com" <= "https://twitter.com"
"https://facebook.com" <= "https://twitter.com"
"https://stackoverflow.com" <= "https://twitter.com"
the result would be true for all statements ('t' character is greater than 'a', 'f' and 's').
Thus:
"https://zwebsite" <= "https://twitter.com"
would returns false ('t' is less than 'z').
However, to get the expected result, you could implement your function like this:
func isValid(_ item: String) -> Bool {
let whitelist = ["https://apple.com","https://facebook.com","https://stackoverflow.com"]
return whitelist.contains { $0 == item }
}
Or for even a shorter contains:
return whitelist.contains(item)
Which leads to let
isValid("https://twitter.com")
to returns false.

Just return the following, which will return true or false:
return whitelist.contains(item)

Related

Putting string variables in array, then comparing different string variable value with variable values in array

I have an angular page, with input fields from which I read input values and set them in variables inside .ts file. The values entered may change, so I cant hard-code values.
These are the variables I set values in using [(ngModel)]. All is good with that, values are set.
input1_1: string;
input1_2: string;
input2_1: string;
input2_2: string;
Then I want to make comparison. All the inputs ending with _1 is put in array fromArray, all other, ending with _2 in toArray.
Then I want to make comparison, because I don't want to have a value from fromArray inside toArray.
In a function I tried doing
if (this.toArray.includes(this.input1_1) == true) {
//then disable next button
}
But it doesn't work. I guess I need to get actual values, because it doesn't seem to be checking for actual values.
How can I manage to check if array of variables has same value as a different variables value?
This is all code together (sample from it, as its checking for other things also in the if statement), should make it clearer.
// input values from angular html input fields
input1_1: string;
input1_2: string;
input2_1: string;
input2_2: string;
input3_1: string;
input3_2: string;
input4_1: string;
input4_2: string;
// arrays for checking
fromArray = [this.input1_1, this.input2_1, this.input3_1, this.input4_1];
toArray = [this.input1_2, this.input2_2, this.input3_2, this.input4_2];
// function to run on each input field
checkValues() {
if (this.toArray.includes(this.input1_1) == true) {
this.disableNext = true
} else (this.disableNext = false)
}
I could have just compared values to each other, but I did not want to write too much code, thought this should be a lot shorter.
I've spent last 2 hours searching for similar examples, but none helped.
I did read about array.some(), but It seems that it wouldnt help me, and would cause extra code write, and array.includes() is a better option.
Any tip would be great.
I'm new to coding, so please be gentle and ask for clarification if needed.
EDIT:
As requested by Jo Carrasco and Dev - I will input the whole thing:
StackBlitz link
The html formatting is totally wrong in stackblitz, but it does what is needed.
The this.toArray.includes(this.input1_1) is only in first dropdown function (checkDropDown1) for now, I dont see need to add to others, as I need to check for only one now.
you can see the logic of disabling Next button also - all values needs to be entered if checkbox is checked, and if they are same in either of the places (either 2 dropdowns are same, or any of input fields), the button needs to be disabled.
EDIT 2
It seems that it doesn't update the values in array once they are dynamically changed. It takes the first value the variable had, and saves that value in array, but doesn't change it when and edit happens on the variable (input field).
-- What I did to fix it is I am splicing array value, so that whenever I call a function which should check the values in array, I am deleting and then inserting that value that I need to update into the array and then do a comparison using if statement inside for. Then I do the check inside the actual if statement with equalValue where the original array.include(); was supposed to be.
this.fromArray.splice(0, 1, this.input1_1);
this.toArray.splice(0, 1, this.input1_2);
var equalValue = false;
for (let i = 0; i < this.toArray.length; i++) {
if( this.toArray[i] === this.input1_1) {
equalValue = true;
console.log(this.toArray[i]);
console.log(this.input1_1);
break;
}
}
If you have a better solution, please write it down, I will go through it and mark as answer if it solves the issue better.
Please show the actual code, so we can run it by ourselves.
It looks like those string properties are undefined.
undefined == true //false
So, that's why you can't get the actual value
Try to do it like this
if (this.toArray.includes(this.input1_1)) {
if you really dont care about exact value but toArray and fromArray should not have any value same then here is your solution-
include loadash in your project loadash - https://lodash.com/docs/4.17.15#uniq
checkValues() {
if (_.uniq([...this.toArray, ...this.fromArray]).length < [...this.toArray, ...this.fromArray].length ) {
this.disableNext = true
} else (this.disableNext = false)
}
explanation -
if both array have some values same-
this.toArray = [a,b,c];
this.toArray = [a,b,d];
[...this.toArray, ...this.fromArray] will equal to [a,b,c,a,b,d] // length will be 6
_.uniq([...this.toArray, ...this.fromArray]) will equal to - [a,b,c,d]; // length will be 4
// so if duplicates is present then left hand will be less than right hand in if statement
if both array have no values same
this.toArray = [a,b,c];
this.toArray = [d,g,f];
[...this.toArray, ...this.fromArray] will equal to [a,b,c,d,g,f] // length will be 6
_.uniq([...this.toArray, ...this.fromArray]) will equal to - [a,b,c,d,g,f]; // length will be 6
// so in this case it will go to false condition
hope it helps Happy coding !! :)
What I did to fix it is I am splicing array value, so that whenever I call a function which should check the values in array, I am deleting and then inserting that value that I need to update into the array and then do a comparison using if statement inside for. Then I do the check inside the actual if statement with equalValue where the original array.include(); was supposed to be.
checkValues() {
this.fromArray.splice(0, 1, this.input1_1);
this.toArray.splice(0, 1, this.input1_2);
var equalValue = false;
for (let i = 0; i < this.toArray.length; i++) {
if( this.toArray[i] === this.input1_1) {
equalValue = true;
console.log(this.toArray[i]);
console.log(this.input1_1);
break;
}
}
if (this.equalValue == true) {
this.disableNext = true
} else (this.disableNext = false)
}
If you have a better solution, please write it down, I will go through it and mark as answer if it solves the issue better.

What is the difference between elementsEqual and '==' in Swift?

I'm going through the Swift Standard Library, and I came across the method elementsEqual for comparing sequences.
I'm not really seeing the value of this function because it will only return true if the order is exactly the same. I figured this would have some use if it could tell me if two sequences contained the same elements, they just happen to be in a different order, as that would save me the trouble of sorting both myself.
Which brings me to my question:
Is there any difference between using elementsEqual and '==' when comparing two sequences? Are there pros and cons for one vs the other?
I am in my playground, and have written the following test:
let values = [1,2,3,4,5,6,7,8,9,10]
let otherValues = [1,2,3,4,5,6,7,8,9,10]
values == otherValues
values.elementsEqual(otherValues)
both of these checks result in true, so I am not able to discern a difference here.
After playing with this for a while to find a practical example for the below original answer I found a much more simple difference: With elementsEqual you can compare collections of different types such as Array, RandomAccessSlice and Set, while with == you can't do that:
let array = [1, 2, 3]
let slice = 1...3
let set: Set<Int> = [1, 2, 3] // remember that Sets are not ordered
array.elementsEqual(slice) // true
array.elementsEqual(set) // false
array == slice // ERROR
array == set // ERROR
As to what exactly is different, #Hamish provided links to the implementation in the comments below, which I will share for better visibility:
elementsEqual
==
My original answer:
Here's a sample playground for you, that illustrates that there is a difference:
import Foundation
struct TestObject: Equatable {
let id: Int
static func ==(lhs: TestObject, rhs: TestObject) -> Bool {
return false
}
}
// TestObjects are never equal - even with the same ID
let test1 = TestObject(id: 1)
let test2 = TestObject(id: 1)
test1 == test2 // returns false
var testArray = [test1, test2]
var copiedTestArray = testArray
testArray == copiedTestArray // returns true
testArray.elementsEqual(copiedTestArray) // returns false
Maybe someone knows for sure, but my guess is that == computes something like memoryLocationIsEqual || elementsEqual (which stops evaluating after the memory location is indeed equal) and elementsEqual skips the memory location part, which makes == faster, but elementsEqual more reliable.

How to check array is not NULL using AngularJS?

I have this array:
var someArr = [1,2,3,4,5];
At some point I need to check that array is not null or length of the array > 0.
What is elegant way to implement it in Angularjs?
You can just check if the variable (array,object anything) has a truthy value or not. That means :
if( value ) {
}
will evaluate to true if value is not:
1. null
2. undefined
3. NaN
4. empty string ("")
5. 0
6. false
This is for above six conditions. But in case you have array define as:
var arr = [];
then you need to check arr.length
This question is more related to JavaScript, not AngularJS.
function nonEmpty(arr) {
return !!arr && arr.length > 0;
}
Examples:
nonEmpty(['a']) // true
nonEmpty([]) // false
nonEmpty(null) // false
nonEmpty(undefined) // false
I guessing you mean something like the following:
angular.isDefined()
Which is archievable by defining it yourself at the root of your application
angular.isNotNullOrZero = function(array) {
return !!array && !!array.length;
}
So you can use it throughout your application.
var someArr = [1,2,3,4,5];
console.log(angular.isNotNullOrZero(someArr);
etc..
But like others said, this is just plain JS.

Swift sort array of objects based on boolean value

I'm looking for a way to sort a Swift array based on a Boolean value.
I've got it working using a cast to NSArray:
var boolSort = NSSortDescriptor(key: "selected", ascending: false)
var array = NSArray(array: results)
return array.sortedArrayUsingDescriptors([boolSort]) as! [VDLProfile]
But I'm looking for the Swift variant, any ideas?
Update
Thanks to Arkku, I've managed to fix this using the following code:
return results.sorted({ (leftProfile, rightProfile) -> Bool in
return leftProfile.selected == true && rightProfile.selected != true
})
Swift's arrays can be sorted in place with sort or to a new array with sorted. The single parameter of either function is a closure taking two elements and returning true if and only if the first is ordered before the second. The shortest way to use the closure's parameters is by referring to them as $0 and $1.
For example (to sort the true booleans first):
// In-place:
array.sort { $0.selected && !$1.selected }
// To a new array:
array.sorted { $0.selected && !$1.selected }
(edit: Updated for Swift 3, 4 and 5, previously sort was sortInPlace and sorted was sort.)
New (for Swift 1.2)
return results.sort { $0.selected && !$1.selected }
Old (for Swift 1.0)
Assuming results is of type [VDLProfile] and VDLProfile has a Bool member selected:
return results.sorted { $0.selected < $1.selected }
See documentation for sorted
Swift’s standard library provides a function called sorted, which sorts an array of values of a known type, based on the output of a sorting closure that you provide
reversed = sorted(array) { $0 > $1 }
reversed will be a new array which will be sorted according to the condition given in the closure.

Swift: optional array count

In Objective-C, if I had the following property:
#property (strong, nonatomic) NSArray * myArray;
A method to return a number of objects in myArray would look like:
- (NSInteger) numberOfObjectsInMyArray
{
return [self.myArray count];
}
This would return either the number of objects in the array, or 0 if myArray == nil;
The best equivalent I can think of for doing this in Swift is:
var myArray: Array<String>?
func numberOfObjectsInMyArray() -> Int
{
return myArray ? myArray!.count : 0
}
So checking the optional array contains a value, and if so unwrap the array and return that value, otherwise return 0.
Is this the correct way to do this? Or is there something simpler?
Try using the nil coalescing operator.
According to the Apple Documentation:
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil.
So your function could look like this:
func numberOfObjectsInMyArray() -> Int {
return (myArray?.count ?? 0)
}
I agree with others that this could be a bad idea for a number of reasons (like making it look like there is an array with a count of "0" when there isn't actually an array at all) but hey, even bad ideas need an implementation.
EDIT:
So I'm adding this because two minutes after I posted this answer, I came across a reason for doing exactly what the author wants to do.
I am implementing the NSOutlineViewDataSource protocol in Swift. One of the functions required by the protocol is:
optional func outlineView(_ outlineView: NSOutlineView,
numberOfChildrenOfItem item: AnyObject?) -> Int
That function requires that you return the number of children of the item parameter. In my code, if the item has any children, they will be stored in an array, var children: [Person]?
I don't initialize that array until I actually add a child to the array.
In other words, at the time that I am providing data to the NSOutlineView, children could be nil or it could be populated, or it could have once been populated but subsequently had all objects removed from it, in which case it won't be nil but it's count will be 0. NSOutlineView doesn't care if children is nil - all it wants to know is how many rows it will need to display the item's children.
So, it makes perfect sense in this situation to return 0 if children is nil. The only reason for calling the function is to determine how many rows NSOutlineView will need. It doesn't care whether the answer is 0 because children is nil or because it is empty.
return (children?.count ?? 0) will do what I need. If children is nil it will return 0. Otherwise it will return count. Perfect!
That looks like the simpler way.
The Objective-C code is shorter only because nil is also a form of 0, being a C-based language.
Since swift is strongly typed you don't have such a shorthand. In this specific case it requires a little more effort, but in general it saves you most of the headaches caused by loose typing.
Concerning the specific case, is there a reason for making the array optional in the first place? You could just have an empty array. Something like this might work for you:
var myArray: Array<String> = []
func numberOfObjectsInMyArray() -> Int {
return myArray.count
}
(Source for this information)
How about using optional for return value?
var myArray: Array<String>?
func numberOfObjectsInMyArray() -> Int? {
return myArray?.count
}
I think that this way is safer.
(Source for this information)

Resources