Compare elements of one array to other two arrays, swift - swift5

enter image description here
I wanted to check if the value array I passed in will be matched or contain the value to the alphabets array, nums array, or both.
the intention of checking this was meant to make a login validation, and I do not want to use the regular expression way to check it, instead I would like to use the current function or loops to solve this question.
the enclosed picture was the approach i have tried. I may have gotten the wrong direction.

Since for character in convertedCharaters picks each elem of the array, it will either be in alphabets or in nums but not in both for sure. That's the mistake in your code.
Here we define to flags (numFound - true if there was a num, letterFound - true if there was a letter) and iterate through all elements of the given array.
If the element is contained by alphabets, we set the result and set the letterFound = true. If the for-loop already found a num, the flag numFound has to be true. Therefore we know that we found both (letter and number), so we can instantly return "contains both".
Same approach if the element is contained by nums.
var result = ""
var numFound = false
var letterFound = false
for character in convertedCharaters {
if alphabets.contain(character) {
result = "contains only letter"
letterFound = true
if numFound {
return = "contains both"
}
} else if nums.contains(characters) {
result = "contains only nums"
numFound = true
if letterFound {
return = "contains both"
}
}
}
return result
Be careful about the case that neither num nor letter was found! I did not consider that.

Related

How can I compare two Arrays in Swift and mutate one of the arrays if two Items are the same

I want to compare two Arrays with each other, that means each single item of them.
I need to run some code if two items in this arrays are the same.
I've done that so far with two For-Loops, but someone in the comments says that's not that good (because I get an Error too.
Has anybody an Idea which Code I can use to reach that?
Btw: That's the code I used before:
var index = 0
for Item1 in Array1 {
for Item2 in Array2 {
if (Item1 == Item2) {
// Here I want to put some code if the items are the same
}
}
// Index is in this case the counter which counts on which place in the Array1 I am.
index += 1
}
Okay I'll try again to describe what I mean:
I want to compare two Arrays. If there are some Items the same, I want to delete that Item from Array A / Array 1.
Okay if that is working, I want to add a few more statements that alow me to delete a Item only if an parameter of this item has a special worth, but I think I can do this step alone.
If you want to compare items from different array you need to add Equatable protocol for your Item
For example:
struct Item: Equatable {
let name: String
static func ==(l: Item, r: Item) -> Bool {
return l.name == r.name
}
}
You need to decide by which attributes you want to compare your Item. In my case I compare by name.
let array1: [Item] = [
.init(name: "John"),
.init(name: "Jack"),
.init(name: "Soer"),
.init(name: "Kate")
]
let array2: [Item] = [
.init(name: "John"),
]
for item1 in array1 {
if array2.contains(item1) {
// Array 2 contains item from the array1 and you can perform your code.
}
}
If you want to support this
Okay I'll try again to describe what I mean: I want to compare two
Arrays. If there are some Items the same, I want to delete that Item
from Array A / Array 1. Okay if that is working, I want to add a few
more statements that alow me to delete a Item only if an parameter of
this item has a special worth, but I think I can do this step alone.
I guess it can fit for you
You need to make your array1 mutable
var array1: [Item] = ...
Filter the array1 like this
let filteredArray1 = array1.filter { (item) -> Bool in
return !array2.contains(item)
}
And redefine your array1 with filtered array.
array1 = filteredArray1
Let me know it it works for you.
var itemsToRemove = array1.filter { array2.contains($0) }
for item in itemsToRemove {
if let i = array1.firstIndex(of: item) {
// run your conditional code here.
array1.remove(at: i)
}
}
Update
The question has been restated that elements are to be removed from one of the arrays.
You don't provide the actual code where you get the index out of bounds error, but it's almost certainly because you don't account for having removed elements when using the index, so you're probably indexing into a region that was valid at the start, but isn't anymore.
My first advice is don't do the actual removal inside the search loop. There is a solution to achieve the same result, which I'll give, but apart from having to be very careful about indexing into the shortened array, there is also a performance issue: Every deletion requires Array to shift all the later elements down one. That means that every deletion is an O(n) operation, which makes an the overall algorithim O(n^3).
So what do you do instead? The simplest method is to create a new array containing only the elements you wish to keep. For example, let's say you want to remove from array1 all elements that are also in array2:
array1 = array1.filter { !array2.contains($0) }
I should note that one of the reasons I kept my original answer below is because you can use those methods to replace array2.contains($0) to achieve better performance in some cases, and the original answer describes those cases and how to achieve it.
Also even though the closure is used to determine whether or not to keep the element, so it has to return a Bool, there is nothing that prevents you from putting additional code in it to do any other work you might want to:
array1 = array1.filter
{
if array2.contains($0)
{
doSomething(with: $0)
return false // don't keep this element
}
return true
}
The same applies to all of the closures below.
You could just use the removeAll(where:) method of Array.
array1.removeAll { array2.contains($0) }
In this case, if the closure returns true, it means "remove this element" which is the opposite sense of the closure used in filter, so you have to take that into account if you do additional work in it.
I haven't looked up how the Swift library implements removeAll(where:) but I'm assuming it does its job the efficient way rather than the naive way. If you find the performance isn't all that good you could roll your own version.
extension Array where Element: Equatable
{
mutating func efficientRemoveAll(where condition: (Element) -> Bool)
{
guard count > 0 else { return }
var i = startIndex
var iEnd = endIndex
while i < iEnd
{
if condition(self[i])
{
iEnd -= 1
swapAt(i, iEnd)
continue // note: skips incrementing i,iEnd has been decremented
}
i += 1
}
removeLast(endIndex - iEnd)
}
}
array1.efficientRemoveAll { array2.contains($0) }
Instead of actually removing the elements inside the loop, this works by swapping them with the end element, and handling when to increment appropriately. This collects the elements to be removed at the end, where they can be removed in one go after the loop finishes. So the deletion is just one O(n) pass at the end, which avoids increasing the algorithmic complexity that removing inside the loop would entail.
Because of the swapping with the current "end" element, this method doesn't preserve the relative order of the elements in the mutating array.
If you want to preserve the order you can do it like this:
extension Array where Element: Equatable
{
mutating func orderPreservingRemoveAll(where condition: (Element) -> Bool)
{
guard count > 0 else { return }
var i = startIndex
var j = i
repeat
{
swapAt(i, j)
if !condition(self[i]) { i += 1 }
j += 1
} while j != endIndex
removeLast(endIndex - i)
}
}
array1.orderPreservingRemoveAll { array2.contains($0) }
If I had to make a bet, this would be very close to how standard Swift's removeAll(where:) for Array is implemented. It keeps two indices, one for the current last element to be kept, i, and one for the next element to be examined, j. This has the effect of accumulating elements to be removed at the end (those past i).
Original answer
The previous solutions are fine for small (yet still surprisingly large) arrays, but they are O(n^2) solutions.
If you're not mutating the arrays, they can be expressed more succinctly
array1.filter { array2.contains($0) }.forEach { doSomething($0) }
where doSomething doesn't actually have to be a function call - just do whatever you want to do with $0 (the common element).
You'll normally get better performance by putting the smaller array inside the filter.
Special cases for sorted arrays
If one of your arrays is sorted, then you might get better performance in a binary search instead of contains, though that will require that your elements conform to Comparable. There isn't a binary search in the Swift Standard Library, and I also couldn't find one in the new swift-algorithms package, so you'd need to implement it yourself:
extension RandomAccessCollection where Element: Comparable, Index == Int
{
func sortedContains(_ element: Element) -> Bool
{
var range = self[...]
while range.count > 0
{
let midPoint = (range.startIndex + range.endIndex) / 2
if range[midPoint] == element { return true }
range = range[midPoint] > element
? self[..<midPoint]
: self[index(after: midPoint)...]
}
return false
}
}
unsortedArray.filter { sortedArray.sortedContains($0) }.forEach { doSomething($0) }
This will give O(n log n) performance. However, you should test it for your actual use case if you really need performance, because binary search is not especially friendly for the CPU's branch predictor, and it doesn't take that many mispredictions to result in slower performance than just doing a linear search.
If both arrays are sorted, you can get even better performance by exploiting that, though again you have to implement the algorithm because it's not supplied by the Swift Standard Library.
extension Array where Element: Comparable
{
// Assumes no duplicates
func sortedIntersection(_ sortedOther: Self) -> Self
{
guard self.count > 0, sortedOther.count > 0 else { return [] }
var common = Self()
common.reserveCapacity(Swift.min(count, sortedOther.count))
var i = self.startIndex
var j = sortedOther.startIndex
var selfValue = self[i]
var otherValue = sortedOther[j]
while true
{
if selfValue == otherValue
{
common.append(selfValue)
i += 1
j += 1
if i == self.endIndex || j == sortedOther.endIndex { break }
selfValue = self[i]
otherValue = sortedOther[j]
continue
}
if selfValue < otherValue
{
i += 1
if i == self.endIndex { break }
selfValue = self[i]
continue
}
j += 1
if j == sortedOther.endIndex { break }
otherValue = sortedOther[j]
}
return common
}
}
array1.sortedIntersection(array2).forEach { doSomething($0) }
This is O(n) and is the most efficient of any of the solutions I'm including, because it makes exactly one pass through both arrays. That's only possible because both of the arrays are sorted.
Special case for large array of Hashable elements
However, if your arrays meet some criteria, you can get O(n) performance by going through Set. Specifically if
The arrays are large
The array elements conform to Hashable
You're not mutating the arrays
Make the larger of the two arrays a Set:
let largeSet = Set(largeArray)
smallArray.filter { largeSet.contains($0) }.forEach { doSomething($0) }
For the sake of analysis if we assume both arrays have n elements, the initializer for the Set will be O(n). The intersection will involve testing each element of the smallArray's elements for membership in largeSet. Each one of those tests is O(1) because Swift implements Set as a hash table. There will be n of those tests, so that's O(n). Then the worst case for forEach will be O(n). So O(n) overall.
There is, of course, overhead in creating the Set, the worst of which is the memory allocation involved, so it's not worth it for small arrays.

if (variable assignment) syntax query (Swift)

I am confused with what exactly this line,
if let fileList = fileList, let files = fileList.files
is doing. If I understand correctly, a conditional can only have a boolean as its parameter, so
let fileList = fileList, let files = fileList.files
should be either true or false. What exactly does this syntax do?
func updateDisplay() {
updateButtons()
if let fileList = fileList, let files = fileList.files {
if files.count == 0 {
output?.text = "Folder is empty"
table?.isHidden = true
} else {
table?.isHidden = false
table?.reloadData()
}
}
else {
output?.text = ""
table?.isHidden = true
}
}
The let a = b syntax used in an if statement is called optional binding. You can read more about it here. Essentially, if b is nil, the condition is treated as "false". If b is not nil, the condition is treated as "true", and a non optional constant a will now have the value that b has, and you can use it inside the if block.
Swift if statements also allow you to specify multiple conditions. All of them has to be "true" for the if block to be executed. These conditions doesn't have to be boolean expressions. They could be any of the following:
Boolean expressions
Optional Binding
#available check
case pattern matching
If you have two boolean expressions and you want to run some code if both of them are true, you could use && to join them together, but if you have 2 optionals that you want to bind, or one boolean expression and one optional binding, or any combination of the above, you'd need to use a comma to separate the conditions.
if let fileList = fileList, let files = fileList.files {
is actually an assignment statement with a test for "null". If the assignment succeeds, then carry out the code inside the braces. The boolean test for equality in swift is ==.

Scala Function founds Unit while i return boolean

Im getting error in if(Liste.length>1), i want to make a function to return true if list is ordered low to high. Having some problems with Boolean returning.
object Soru5 extends App {
//A function returns true if list is ordered low to high
def kucukten_buyuge_siralimi(Liste:List[Int]):Boolean=
{
var i=0
var ListeIslem=Liste
if(Liste.length==0) false
if(Liste.length==1) true
if(Liste.length>1) //***********ERROR************ found->Unit,Boolean required
{
while(i<Liste.length-1)
{
var onceki=ListeIslem.head //onceki is first element of list
var sonraki=(ListeIslem.tail).head //sonraki is second element of list
if(onceki>sonraki)
{
return false
}
else
{
ListeIslem=ListeIslem.tail
i=i+1
}
}
return true
}
}
val listem=List(3,2,1)
println(kucukten_buyuge_siralimi(listem))
}
The return value of a method is the value of the last expression evaluated inside the method body. In your case, the last expression inside the method body is:
if(Liste.length>1) {
// …
}
So … what is the value of this expression if the length is less than 2? There is no value! Actually, in Scala, there is (almost) always a value, so the value of this is () which is of type Unit and denotes the absence of a value.
In other words, if the length is less than 2, your method will return () of type Unit, but it promises to return something of type Boolean. You need to add an else clause to your if expression that also returns a Boolean.
This is the immediate cause of the error.
Note that there are also some other problems with your code besides that. For example, those two lines don't actually do anything:
if(Liste.length==0) false
if(Liste.length==1) true
They simply evaluate to a value, but you don't actually do anything with that value, you don't store it in a variable, you don't return it, you don't pass it as an argument … it just vanishes.
Note also that your code violates the Community Coding Style.
And last but not least, your code just doesn't read like Scala. It reads more like a mix of Fortran and Basic. Scala style would be more like this:
def isMonotonicallyIncreasing(l: List[Int]) =
if (l.size < 2) true else l.sliding(2).forall { case (a :: b :: Nil) ⇒ a <= b }
i.e. a list is monotonically increasing if for all subsequent pairs of elements, the left element is not greater than the right element.
Because there's no else between ifs, they are separate. You effectively have
if (Liste.length==0) false else ();
if (Liste.length==1) true else ();
if (Liste.length>1) ... else ();
else () is what the compiler inserts for every if without else.
The compiler has no idea that Liste.length will be the same each time or that it will never be negative. It would be better to write
Liste.length match {
case 0 => false
case 1 => true
case n => ...
You can use n in the last branch instead of calculating length yet again.
This can be improved further, of course, but I think it's out of scope for this answer.

Binary operator '==' cannot be applied to operands of type '[String]' and 'String

I am new to coding and I needed some help with answering this challenge.
Instructions:
// Given the two arrays below, write a function that takes a String as an input parameter and returns a Boolean value. The function should return true if the String input is in either array and it should return false if the String input is in neither array.
//
// Examples:
// Call your function and pass in the String "cat" as the input. Your function should return true
// Call your function and pass in the String "cow" as the input. Your function should return false
let array1 = ["dog", "cat", "bird", "pig"]
let array2 = ["turtle", "snake", "lizard", "shark"]
// Write your function below:
Here is where I have written my function:
func test(Animal:String){
let list = array1 + array2
for animal in list {
if list == animal {
print("true")
} else {
print("false")
}
}
}
test(Animal: "dog")
The error I am getting is:
Binary operator '==' cannot be applied to operands of type '[String]' and 'String under the if statement.
Help if you can and I apologize in advance if this is not formatted correctly.
Thanks!
Just a tip, in the future you should try adding a more descriptive question title, that is super vague and could mean anything.
Anyways your issue is with the line:
if list == animal {
The error you got is quite specific and tells you exactly what's going wrong. [String] is an array of strings while String is just a single item. So when you write for animal in list your taking one animal in that list at a time.
Comparing an animal to a list is not allowed. They are not the same type ([String] and String are different types, as the compiler error told you). You can only compare variables of the same type. So in your case a list (String array aka [String]) to a another list, or an animal (String) to an animal.
Now what you want to do is see if a string you got is in either array. There's actually a built in method in arrays that lets you do exactly this: .contains
func test(animal:String){
let list = array1 + array2
if list.contains(animal) {
print("true")
} else {
print("false")
}
}
or if you want to be extra concise with some good code you can try
func test(animal:String){
let list = array1 + array2
print(list.contains(animal)) // will be false if it doesn't so prints false, true if it does so prints true.
}
And another side note.. You want to be very careful doing an if else inside of a for loop where both the if and the else return. You shouldn't be making decisions after looking at only ONE element.
Because typically you want to check EVERY value before printing false, but when you have an if else, you'll return/print after checking ONLY the first value.
if you wanted to do it your way (no built in methods, iterating through the array) you would want to do something like this:
func test(animal:String){
let list = array1 + array2
for candidate in list {
if animal == candidate { // there's a match! we can return true
print("true ")
return // return says to exit the function since we no longer need to keep going this is appropriate
}
} // for loop ends
// we only return false once the ENTIRE for loop has run, because we know if it did exist, we would never get to this point in the code
// this part only runs once EVERY item has been checked and none were a match
print("false")
}
And finally as bilal says, never start variable names with capital letters. Typically capital letters mean its a type (like String). You'll notice I renamed Animal -> animal for you in my examples

Argument labels do not match any availble overloads

I'm trying to create an anagram tester, and I'm pretty sure the code I have should work, but I'm getting an error 'Argument labels '(_:)' do not match any available overloads' I've looked at the other posts regarding the same error, but I'm still not sure what this means or how to fix it.
var anagram1 : String!
var anagram2 : String!
var failure : Bool = false
var counter : Int = 0
print("Please enter first word: ")
anagram1 = readLine()
print("Please enter Second word: ")
anagram2 = readLine()
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
anagram2.remove(at: String.Index(counter)) // error here
}
}
}
else {
print("these words are not anagrams")
break;
}
}
if (!failure) {
print("these words ARE anagrams")
}
}
else{
print ("these words aren't even the same length you fucking nonce")
}
To answer your first question: the error message Argument labels '(_:)' do not match any available overloads means that you've given a function parameter names or types that don't match anything Swift knows about.
The compiler is also trying to tell you what parameters to look at. '(_:)' says that you're calling a function with an unlabeled parameter. (That means a value without any parameter name. A common example of a function that would look like this is print("something"). In Swift documentation, this would look like print(_:).
Finally, overloads are ways to call a function with different information. Again using the print function as an example, you can call it multiple ways. A couple of the most common overloads would be:
// print something, followed by a newline character
print("something")
// print something, but stay on the same line
// (end with an empty string instead of the default newline character)
print("something", terminator: "")
Documented, these might look like print(_:) and print(_:, terminator:).
Note: these are broken down for explanation. The actual Swift documentation shows func print(_: Any..., separator: String, terminator: String) which covers a number of different overloads!
Looking at the line where the error occurs, you see a function call and an initializer (which is essentially a function). Documented, the way you've entered the parameters, the functions would look like: remove(at:) and String.Index(_:).
String.Index(_:) matches the parameters of the error message, so that's where your error is. There is no overload of the String.Index initializer that takes an unnamed parameter.
To fix this error, you need to find the correct way to create a String.Index parameter for the remove(at:) function. One way might be to try something like this:
for y in anagram2.characters.enumerated() {
// `y` now represents a `tuple`: (offset: Int, element: Character)
// so, you don't need `counter` anymore; use `offset` instead
if i == y.element { //`i` is a Character, so it can compare to `element`
...
let yIndex: String.Index = anagram2.index(anagram2.startIndex, offsetBy: y.offset)
anagram2.remove(at: yIndex)
...
}
}
However, there are other issues with your code that will cause further errors.
For one, you're looping through a string (anagram2) and trying to change it at the same time - not a good thing to do.
Good luck to you in solving the anagram problem!
Thanks for the help Leo but I found a way of doing it :)
if anagram1.count == anagram2.count {
for i in anagram1.characters{
if (!failure){
counter = -1
failure = true
for y in anagram2.characters {
counter += 1
if i == y {
failure = false
if counter < anagram2.count {
anagram2.remove(at: (anagram2.index(anagram2.startIndex, offsetBy: counter)))
break;
}
}
}
}