Related
I would like help with the following situation
I have two lists:
Situation 1:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 1, 2, 3, 5, 5, 6, 7, 8, 9]
I need key output: Key 4 is different
Situation 2:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
I need key output: false -> no key is different
Situation 3:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 9, 2, 3, 4, 5, 6, 7, 3, 9]
I need key output: Key 1 and Key 8 is different
How could I resolve this? My array has 260 keys
You can use a list comprehension with zip, and enumerate to get the indices. Use short-circuiting and the fact that an empty list is falsy to get False:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 1, 2, 3, 5, 5, 6, 7, 8, 9]
out = [i for i,(e1,e2) in enumerate(zip(a,b)) if e1!=e2] or False
output:
[4]
output for example #2: False
output for example #3: [1, 8]
An approach with itertools.compress. Compare the lists to check difference in values, pass the result of the comparison to compress which will pick-up only the True ones.
from itertools import compress
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0, 1, 2, 3, 5, 5, 6, 7, 8, 9]
result = tuple(compress(a, map(int.__ne__, a, b)))
if not result:
print(False)
else:
print(result)
The current answer is really good, but for an approach which doesn't need zip/enumerate, loop like this:
lista = []
listb = []
unequal_keys = []
for idx in range(len(lista)):
if lista[idx] != listb[idx]:
unequal_keys.append(idx)
if unequal_keys == []:
print(False)
else:
print(unequal_keys)
I recommend learning new techniques and using build ins like zip and enumerate though. They are much more pythonic and faster!
list_1 =[1,2,3,4,5,6,7,8,9,10]
how can i get the above list in the form of below list (repeatation needed for first 5 elements only)
list_1 =[1,1,2,2,3,3,4,4,5,5,6,7,8,9,10]
list_1 =[1,2,3,4,5,6,7,8,9,10]
for index in range(0, 10, 2):
list_1.insert(index, list_1[index])
print(list_1)
Output:
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10]
Since good answers have been given here is a one line way to do this
import itertools
list_1 =[1,2,3,4,5,6,7,8,9,10]
new_list = [val for pair in itertools.zip_longest(list_1,list_1[:5],fillvalue='-' for val in pair if val != '-']
print(new_list)
output [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10]
Is this an alright way to bring equal elements together (make them appear consecutively in the list)?
>>> a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
>>> for x in reversed(a):
a.remove(x)
a.append(x)
>>> a
[8, 8, 8, 8, 2, 2, 2, 1, 1, 7]
Edit: List where it allegedly doesn't work (see comments):
>>> a = [2, 7, 1, 1, 8, 2, 8, 1, 8, 2, 8]
>>> for x in reversed(a):
a.remove(x)
a.append(x)
>>> a
[8, 8, 8, 8, 2, 2, 2, 1, 1, 1, 7]
Just use list.sort:
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort()
print(a)
Output:
[1, 1, 2, 2, 2, 7, 8, 8, 8, 8]
If u want it in descending order, then pass reverse = True to list.sort:
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
a.sort(reverse = True)
print(a)
Output:
[8, 8, 8, 8, 7, 2, 2, 2, 1, 1]
Another solution, giving no guarantee on the order of the output, but that is O(n) instead O(n*log(n)) for the solution using sort: count the values, and create a new list with the corresponding counts for each value:
from collections import Counter
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
counts = Counter(a)
out = []
for value, count in counts.items():
out.extend([value]*count)
print(out)
# [2, 2, 2, 7, 1, 1, 8, 8, 8, 8]
As suggested by #Manuel, there is a Counter method that I had never noticed, Counter.elements():
Return an iterator over elements repeating each as many times as its count. Elements are returned in the order first encountered
So, to get an output in original order, and in O(n), the code would be simply:
from collections import Counter
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
out = list(Counter(a).elements())
print(out)
# [2, 2, 2, 7, 1, 1, 8, 8, 8, 8]
Why/how it works, and about this possibly being an undefined implementation detail:
The iterator starts at the end:
iterator
↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = undefined
Then the for loop asks the iterator for an item. After getting the last 8, the iterator decreases its index into the list and returns the 8 (code), which the for loop stores in x. So now we have:
↓
a = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
x = 8
Then a.remove(x) removes the first 8, which shifts all later items to the left:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8]
x = 8
And a.append(x) appends it at the end:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8
Then the for loop gets the next item from the iterator, which is the same 8 as before, only at the lower index:
↓
a = [2, 7, 1, 2, 8, 1, 8, 2, 8, 8]
x = 8 (same one again)
The remove again removes the first 8 (which was originally the second 8):
↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8]
And it gets appended:
↓
a = [2, 7, 1, 2, 1, 8, 2, 8, 8, 8]
The next round moves the originally third 8 to the end:
↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]
And then finally the originally fourth 8 (which we've been finding over and over again) moves as well:
↓
a = [2, 7, 1, 2, 1, 2, 8, 8, 8, 8]
The same then happens to the 2's, 1's and the 7, so we end up with:
a = [8, 8, 8, 8, 2, 2, 2, 1, 1, 7]
JBernardo commented that it "could be undefined behavior on a different python implementation". I guess it could be, but I'd blame that implementation. The Python reference documentation notes (although about the forward iterator):
There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop.
And that's not marked as a CPython implementation detail, which the Python documentation does at plenty of other places: 261 results for googling site:docs.python.org/3/ "CPython implementation detail"
I'm looking to slice a list across two or more slices. For example, there is a list:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Let's say I want to slice the list as items 1 to 4 and 6 to 9.
If we do:
a[1:5]
the output:
[1, 2, 3, 4]
If we do:
a[6:10]
the output is:
[6, 7, 8, 9]
But is there someway to combine multiple slices. Something like:
a[1:5 and 6:10]
to output:
[1, 2, 3, 4, 6, 7, 8, 9]
There is no special syntax, just append the lists slices:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 4, 6, 7, 8, 9]
print(a[1:5]+a[6:10])
If you want to avoid creating the intermediate lists for the individual slices, you could use itertools.islice and chain.from_iterable to get and combine the slices as iterators.
>>> from itertools import chain, islice
>>> slc = [(1,5), (6,10)]
>>> list(chain.from_iterable(islice(a, *s) for s in slc))
[1, 2, 3, 4, 6, 7, 8, 9]
Also works with 1- or 3-tuples, for just end-, or start-end-step slices.
Based on napuzba's suggestion, I'm thinking that the following might be the most efficient way to do this:
all_slice = [*a[1:5], *a[6:10]]
Where all_slice holds:
[1, 2, 3, 4, 6, 7, 8, 9]
This seems pretty pythonic.
You can use list.extend for this task.
slice1 = a[1:5]
slice2 = a[6:10]
slice1.extend(slice2)
# now use slice1
It appends all the items of the slice2 to the first slice1.
If you have several ranges you are trying to slice, you can use the built-in slice() with a list comprehension:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ranges = [(1, 5), (6, 10)]
[n for s in ranges for n in a[slice(*s)]]
# [1, 2, 3, 4, 6, 7, 8, 9]
Inspired by the answer:
There is no special syntax, just append the lists slices:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[1:5]+a[6:10])
FROM -> Aviv Yaniv
b, a = a[1:5], a[6:10]
print(b+a)
new_list = []
i = 0
def remove_adjacent(nums):
global i
while i < len(nums) - 1:
if nums[i] != nums[i+1]:
new_list.append(nums[i])
else:
i += 1
remove_adjacent(nums[i:])
return
i += 1
l = [1, 2, 3, 5, 4, 4, 5, 5, 6, 7, 7, 7, 8, 8, 9, 8, 8]
remove_adjacent(l)
print new_list
Question: Given a list of numbers, return a list where all adjacent == elements have been reduced to a single element, so [1, 2, 2, 3] returns [1, 2, 3]. You may create a new list or modify the passed in list.
Issue: The final list printed consists of [1, 2, 3, 5] instead of [1, 2, 3, 5, 4, 5, 6, 7, 8, 9, 8]
What you would want is a problem best solved by itertools.groupby
l
Out[35]: [1, 2, 3, 5, 4, 4, 5, 5, 6, 7, 7, 7, 8, 8, 9, 8, 8]
from itertools import groupby
[k for k, _ in groupby(l)]
Out[36]: [1, 2, 3, 5, 4, 5, 6, 7, 8, 9, 8]
What itertools.groupby does is, it groups consecutive keys together by generating a tuple of the element and the consecutive group as a list
To get a clear understanding of itertools.groupby, you can dump the resultant list of tuples generated by grouping the list of consecutive numbers
[(k, list(g)) for k, g in groupby(l)]
Out[40]:
[(1, [1]),
(2, [2]),
(3, [3]),
(5, [5]),
(4, [4, 4]),
(5, [5, 5]),
(6, [6]),
(7, [7, 7, 7]),
(8, [8, 8]),
(9, [9]),
(8, [8, 8])]
new_list = []
def remove_adjacent(nums):
i = 0
while i < len(nums) - 1:
if nums[i] != nums[i+1]:
new_list.append(nums[i])
else:
i += 1
remove_adjacent(nums[i:])
return
i += 1
l = [1, 2, 3, 5, 4, 4, 5, 5, 6, 7, 7, 7, 8, 8, 9, 8, 8]
remove_adjacent(l)
# appending the last item
new_list.append(l[len(l)-1])
print (new_list.append(nums[len(nums) - 1]))
Output
[1, 2, 3, 5, 4, 5, 6, 7, 8, 9, 8]
This is perfect for a generator. I'm not altering the original list. Instead, I'm returning a new list with no adjacent values equal to one another.
def removerator(l):
last = None
for x in l:
if x != last:
last = x
yield x
list(removerator(l))
[1, 2, 3, 5, 4, 5, 6, 7, 8, 9, 8]
Setup
l = [1, 2, 3, 5, 4, 4, 5, 5, 6, 7, 7, 7, 8, 8, 9, 8, 8]
I made a function where it get a list and iterate over its items, then it adds the items that aren't the same as the items already added to the list in the previous iteration.
l = [1, 2, 3, 5, 4, 4, 5, 5, 6, 7, 7, 7, 8, 8, 9, 8, 8] # List that we want to change
def remove_adjacent(l): # Define a new function and accept an argument: the list to check.
new = [l[0]] # Make a new list (temporal) and assing like it's first item the first item of the main list. It's the same as new = [] and new.append(l[0]).
for item in l[1:]: # We iterate across the list, but we don't iterate on the first item because we've alreaday added it to the list, if you want you can delete the slice in [1:] since it will only make the iteration a really small fraction more slowly.
if new[-1] != item: # We check if the new item is the same as the last item added to the new list, if not, we add it.
new.append(item) # We add the item to the new list.
return new # We return the list.
print(remove_adjacent(l)) # We check it.
# [1, 2, 3, 5, 4, 5, 6, 7, 8, 9, 8]