If I have two lists for example list1 and list2 how would I search list1 to see if there were any elements which were not in list2 then append it to list2. as an example here are both lists:
let list1 = ["James","John","fat","cart"]
var list2 = ["James","fat","bobby"]
therefore after the algorithm list2 would be:
["James","fat","bobby","John,"cart"]
for value in list1 {
if !list2.contains(value) {
list2.append(value)
}
}
OR
list1.forEach({ !list2.contains($0) ? list2.append($0) : nil })
OR
list2.append(contentsOf: Set(list1).subtracting(Set(list2)))
Use a foreach loop to iterate through the items in list1. If list2 does not contain an item, then append it to list2.*
You can do it one line coding
let list1 = ["James","John","fat","cart"]
var list2 = ["James","fat","bobby"]
list2.append(contentsOf: list1.filter{!list2.contains($0)})
print("\list2")
//output
["James", "fat", "bobby", "John", "cart"]
Most of the answers so far will have poor performance on large arrays.
The Array.contains(_:) method has O(n) performance, meaning that combining 2 arrays will have O(n•m) performance (where n is the number of items in one array and m is the number of items in the other array.) This the time performance will deteriorate exponentially as the arrays grow in size.
If you only need to deal with a handful of items, this doesn't matter. But with >= hundreds of items in the arrays the time performance will get bad fast.
Better to use Sets:
let list1 = ["James","John","fat","cart"]
var list2 = ["James","fat","bobby"]
list2 = Array(Set(list1).union(Set(list2)))
print(Set([list1, list2]))
print(list2)
Sets use hashes for contains/uniqueness testing, which runs in ≈ constant time.
Jorgandar's answer should have good time-performance as well, but mine is a little simpler and (I think) more straightforward to understand.
I just convert each array into a Set, combine them with Set.union(_:), and then convert the results back to a set.
If preserving the original order is important then you could build sets out of each array for uniqueness testing and then loop through one of the arrays using the sets to tell if each item needs to be added to the other array. That would be a little more complex but should give ≈O(n) performance and preserve array ordering.
You need to use Set like this way:
let list1 = ["James","John","fat","cart"]
let list2 = ["James","fat","bobby"]
let final = Array(Set([list1, list2].flatMap({$0})))
Or
let final = Array(Set(list1 + list2))
Related
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 7 years ago.
I have a list
a = ["a", "b", "c", "d", "e"]
I want to remove elements in this list in a for loop like below:
for item in a:
print(item)
a.remove(item)
But it doesn't work. What can I do?
You are not permitted to remove elements from the list while iterating over it using a for loop.
The best way to rewrite the code depends on what it is you're trying to do.
For example, your code is equivalent to:
for item in a:
print(item)
a[:] = []
Alternatively, you could use a while loop:
while a:
print(a.pop())
I'm trying to remove items if they match a condition. Then I go to next item.
You could copy every element that doesn't match the condition into a second list:
result = []
for item in a:
if condition is False:
result.append(item)
a = result
Alternatively, you could use filter or a list comprehension and assign the result back to a:
a = filter(lambda item:... , a)
or
a = [item for item in a if ...]
where ... stands for the condition that you need to check.
Iterate through a copy of the list:
>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
print(item)
if item == "b":
a.remove(item)
a
b
c
d
e
>>> print(a)
['a', 'c', 'd', 'e']
As other answers have said, the best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable. The difference between these depends on your use case, since they affect other variables for the original list differently (or, rather, the first affects them, the second doesn't).
If a copy isn't an option for some reason, you do have one other option that relies on an understanding of why modifying a list you're iterating breaks. List iteration works by keeping track of an index, incrementing it each time around the loop until it falls off the end of the list. So, if you remove at (or before) the current index, everything from that point until the end shifts one spot to the left. But the iterator doesn't know about this, and effectively skips the next element since it is now at the current index rather than the next one. However, removing things that are after the current index doesn't affect things.
This implies that if you iterate the list back to front, if you remove an item at the current index, everything to it's right shifts left - but that doesn't matter, since you've already dealt with all the elements to the right of the current position, and you're moving left - the next element to the left is unaffected by the change, and so the iterator gives you the element you expect.
TL;DR:
>>> a = list(range(5))
>>> for b in reversed(a):
if b == 3:
a.remove(b)
>>> a
[0, 1, 2, 4]
However, making a copy is usually better in terms of making your code easy to read. I only mention this possibility for sake of completeness.
import copy
a = ["a", "b", "c", "d", "e"]
b = copy.copy(a)
for item in a:
print(item)
b.remove(item)
a = copy.copy(b)
Works: to avoid changing the list you are iterating on, you make a copy of a, iterate over it and remove the items from b. Then you copy b (the altered copy) back to a.
How about creating a new list and adding elements you want to that new list. You cannot remove elements while iterating through a list
Probably a bit late to answer this but I just found this thread and I had created my own code for it previously...
list = [1,2,3,4,5]
deleteList = []
processNo = 0
for item in list:
if condition:
print(item)
deleteList.insert(0, processNo)
processNo += 1
if len(deleteList) > 0:
for item in deleteList:
del list[item]
It may be a long way of doing it but seems to work well. I create a second list that only holds numbers that relate to the list item to delete. Note the "insert" inserts the list item number at position 0 and pushes the remainder along so when deleting the items, the list is deleted from the highest number back to the lowest number so the list stays in sequence.
I have two lists:
a = [1,2,3,4,5]
b = [1,4,5]
I want to get the values from list a that do not exist in list b:
result = [2,3]
There are various ways to achieve that and which one fits your situation depends on your requirements (which are not specified in the question).
Do you want to preserve duplicates in a or not:
a = [1,2,2,3,4,5]
b = [1,4,5]
Should this result in [2,3] or [2,2,3]?
If you do not want to preserve duplicates you can convert your lists to Sets and use the difference method:
result = a.toSet().difference(b.toSet())
Our if you want to preserve the duplicates just filter the list.
result = a.filter((v) => b.contains(v))
What I want to do is populate an Array (sequence) by appending in the elements of another Array (availableExercises), one by one. I want to do it one by one because the sequence has to hold a given number of items. The available exercises list is in nature finite, and I want to use its elements as many times as I want, as opposed to a multiple number of the available list total.
The current code included does exactly that and works. It is possible to just paste that in a Playground to see it at work.
My question is: Is there a better Swift3 way to achieve the same result? Although the code works, I'd like to not need the variable i. Swift3 allows for structured code like closures and I'm failing to see how I could use them better. It seems to me there would be a better structure for this which is just out of reach at the moment.
Here's the code:
import UIKit
let repTime = 20 //seconds
let restTime = 10 //seconds
let woDuration = 3 //minutes
let totalWOTime = woDuration * 60
let sessionTime = repTime + restTime
let totalSessions = totalWOTime / sessionTime
let availableExercises = ["push up","deep squat","burpee","HHSA plank"]
var sequence = [String]()
var i = 0
while sequence.count < totalSessions {
if i < availableExercises.count {
sequence.append(availableExercises[i])
i += 1
}
else { i = 0 }
}
sequence
You can overcome from i using modulo of sequence.count % availableExercises.count like this way.
var sequence = [String]()
while(sequence.count < totalSessions) {
let currentIndex = sequence.count % availableExercises.count
sequence.append(availableExercises[currentIndex])
}
print(sequence)
//["push up", "deep squat", "burpee", "HHSA plank", "push up", "deep squat"]
You can condense your logic by using map(_:) and the remainder operator %:
let sequence = (0..<totalSessions).map {
availableExercises[$0 % availableExercises.count]
}
map(_:) will iterate from 0 up to (but not including) totalSessions, and for each index, the corresponding element in availableExercises will be used in the result, with the remainder operator allowing you to 'wrap around' once you reach the end of availableExercises.
This also has the advantage of preallocating the resultant array (which map(_:) will do for you), preventing it from being needlessly re-allocated upon appending.
Personally, Nirav's solution is probably the best, but I can't help offering this solution, particularly because it demonstrates (pseudo-)infinite lazy sequences in Swift:
Array(
repeatElement(availableExercises, count: .max)
.joined()
.prefix(totalSessions))
If you just want to iterate over this, you of course don't need the Array(), you can leave the whole thing lazy. Wrapping it up in Array() just forces it to evaluate immediately ("strictly") and avoids the crazy BidirectionalSlice<FlattenBidirectionalCollection<Repeated<Array<String>>>> type.
I'm getting data from my database in the reverse order of how I need it to be. In order to correctly order it I have a couple choices: I can insert each new piece of data gotten at index 0 of my array, or just append it then reverse the array at the end. Something like this:
let data = ["data1", "data2", "data3", "data4", "data5", "data6"]
var reversedArray = [String]()
for var item in data {
reversedArray.insert(item, 0)
}
// OR
reversedArray = data.reverse()
Which one of these options would be faster? Would there be any significant difference between the 2 as the number of items increased?
Appending new elements has an amortized complexity of roughly O(1). According to the documentation, reversing an array has also a constant complexity.
Insertion has a complexity O(n), where n is the length of the array and you're inserting all elements one by one.
So appending and then reversing should be faster. But you won't see a noticeable difference if you're only dealing with a few dozen elements.
Creating the array by repeatedly inserting items at the beginning will be slowest because it will take time proportional to the square of the number of items involved.
(Clarification: I mean building the entire array reversed will take time proportional to n^2, because each insert will take time proportional to the number of items currently in the array, which will therefore be 1 + 2 + 3 + ... + n which is proportional to n squared)
Reversing the array after building it will be much faster because it will take time proportional to the number of items involved.
Just accessing the items in reverse order will be even faster because you avoid reversing the array.
Look up 'big O notation' for more information. Also note that an algorithm with O(n^2) runtime can outperform one with O(n) for small values of n.
My test results…
do {
let start = Date()
(1..<100).forEach { _ in
for var item in data {
reversedArray.insert(item, at: 0)
}
}
print("First: \(Date().timeIntervalSince1970 - start.timeIntervalSince1970)")
}
do {
let start = Date()
(1..<100).forEach { _ in
reversedArray = data.reversed()
}
print("Second: \(Date().timeIntervalSince1970 - start.timeIntervalSince1970)")
}
First: 0.0124959945678711
Second: 0.00890707969665527
Interestingly, running them 10,000 times…
First: 7.67399883270264
Second: 0.0903480052947998
I'm pretty new to Scala but I like to know what is the preferred way of solving this problem. Say I have a list of items and I want to know the total amount of the items that are checks. I could do something like so:
val total = items.filter(_.itemType == CHECK).map(._amount).sum
That would give me what I need, the sum of all checks in a immutable variable. But it does it with what seems like 3 iterations. Once to filter the checks, again to map the amounts and then the sum. Another way would be to do something like:
var total = new BigDecimal(0)
for (
item <- items
if item.itemType == CHECK
) total += item.amount
This gives me the same result but with 1 iteration and a mutable variable which seems fine too. But if I wanted to to extract more information, say the total number of checks, that would require more counters or mutable variables but I wouldn't have to iterate over the list again. Doesn't seem like the "functional" way of achieving what I need.
var numOfChecks = 0
var total = new BigDecimal(0)
items.foreach { item =>
if (item.itemType == CHECK) {
numOfChecks += 1
total += item.amount
}
}
So if you find yourself needing a bunch of counters or totals on a list is it preferred to keep mutable variables or not worry about it do something along the lines of:
val checks = items.filter(_.itemType == CHECK)
val total = checks.map(_.amount).sum
return (checks.size, total)
which seems easier to read and only uses vals
Another way of solving your problem in one iteration would be to use views or iterators:
items.iterator.filter(_.itemType == CHECK).map(._amount).sum
or
items.view.filter(_.itemType == CHECK).map(._amount).sum
This way the evaluation of the expression is delayed until the call of sum.
If your items are case classes you could also write it like this:
items.iterator collect { case Item(amount, CHECK) => amount } sum
I find that speaking of doing "three iterations" is a bit misleading -- after all, each iteration does less work than a single iteration with everything. So it doesn't automatically follows that iterating three times will take longer than iterating once.
Creating temporary objects, now that is a concern, because you'll be hitting memory (even if cached), which isn't the case of the single iteration. In those cases, view will help, even though it adds more method calls to do the same work. Hopefully, JVM will optimize that away. See Moritz's answer for more information on views.
You may use foldLeft for that:
(0 /: items) ((total, item) =>
if(item.itemType == CHECK)
total + item.amount
else
total
)
The following code will return a tuple (number of checks -> sum of amounts):
((0, 0) /: items) ((total, item) =>
if(item.itemType == CHECK)
(total._1 + 1, total._2 + item.amount)
else
total
)