This question already has answers here:
Check for presence of a sliced list in Python
(11 answers)
Closed 9 years ago.
I am not sure if this question has been asked before but I couldn't find anything similar from the question list. I would like to check if a list has a set of three values in a certain order. For example, I would like to check if an int list has a set of values 1, 2, 3 anywhere within that list. The length of the list is unknown and the list cannot be sorted.
Example:
Values to check: 1, 2, 3 (in this order)
Example of a list = [1, 1, 2, 3, 1]
This is what I have tried so far.
list1 = [1, 1, 2, 3, 1]
list2 = [1, 1, 4, 3, 1, 2, 1]
def checkValue:
for i in range (0, len(nums)):
if (nums[i+2] - nums[i+1] == nums[i+1] - nums[i]) == 1:
return True
return False
list1 --> return True
list2 ---> IndexError: list index out of range
EDIT: Thanks to those who answered and thank you for the list to the sublist question. I never thought that the set of integers can be considered as a sublist and use it to compare to a larger list.
It looks like you're searching a sequence in a list.
You can just compare parts of the list with the sequence.
def find_sequence_in_list(list_to_check, values):
for i in range (len(list_to_check) - len(values) + 1):
#print(list_to_check[i:i + len(values)])
if list_to_check[i:i + len(values)] == values:
return True
return False
values = [1, 2, 3]
data1 = [1, 1, 2, 3, 1]
data2 = [1, 1, 4, 3, 1, 2, 1]
print(find_sequence_in_list(data1, values))
print(find_sequence_in_list(data2, values))
Uncomment the print to see what's happening.
i + 2 is too large in the loop body, nums doesn't have that many elements. Fix it like this:
if i + 2 < len(nums) and (nums[i+2] - nums[i+1] == nums[i+1] - nums[i]) == 1:
...
You can use tuple comparison directly, along with zip iteration (or itertools.izip if you prefer, for general iterables):
>>> def findin(values, nums):
... t = tuple(values)
... return any(T == t for T in zip(*(nums[i:] for i in xrange(values))))
Which gives for your examples:
>>> findin([1,2,3], [1,1,2,3,1])
True
>>> findin([1,2,3], [1, 1, 4, 3, 1, 2, 1])
False
I'm thinking of using deque to the sublist comparison.
from collections import deque
def has_sublist(lst, sub):
tmp_q = deque([], maxlen=len(sub))
sub_q = deque(sub)
for i in nums:
if tmp_q == sub_q:
return True
else:
tmp_q.append(i)
return tmp_q == sub_q
The tmp_q has a max length of len(sub) (which is 3 in your example), it contains a sublist of list to search in.
Let's check if it works well:
>>> lst = [1, 1, 4, 3, 1, 2, 1]
>>> sub = [1, 2, 3]
>>> print has_sublist(lst, sub)
False
>>> lst = [1, 1, 4, 3, 1, 2, 3]
>>> print has_sublist(lst, sub)
True
>>> lst = [1, 2]
>>> print find(lst, sub)
False
>>> lst = [1, 2, 3]
>>> print has_sublist(lst, sub)
True
In this case, you have no need to worry about the IndexError.
Related
I am trying to solve this question "Good array is the array that does not contain any equal adjacent elements.
Given an integer array A of length N, you are asked to do some operations (possibly zero) to make the
array good. One operation is to remove two equal adjacent elements and concatenate the rest of the array.
A : (1, 2, 2, 3, 4)
An after-one operation : (1, 3, 4)
" With python list, as follow:
L=[]
n=int(input("Enter a num"))
for _ in range(n):
x=int(input())
L.append(x)
print(L)
for z in range(L):
if L[z]==L[z+1]:
L.remove(z)
L.remove(z+1)
print(L)
I keep getting this error: Input In [37]
if L[z]==L[z+1]
^
SyntaxError: invalid syntax
any solutions!!`
Easiest solution is to groupby the array and just keep the groups with only one item:
>>> A = [1, 2, 2, 3, 4]
>>> import itertools
>>> A = [i for i, g in itertools.groupby(A) if len(list(g)) == 1]
>>> A
[1, 3, 4]
Edit
This is NOT correct solution of the above problem. It removes contiguous duplicates from the list. But in question, we need to keep 1 instance of duplicate element.
Please refer to #funnydman solution. Thanks #funnydman for pointing out the mistake :)
You are iterating the list and deleting items from the same :|
Not a good idea!
You can use another list to store the result.
result = []
for z in range(len(L)-1):
if L[z]!=L[z+1]:
result.append(L[z])
result.append(L[-1])
Unfortunately, Nawal's solution does not produce the correct answer, I would suggest this approach:
def get_good_array(alist):
result = []
L = alist + [None]
i = 0
while i < len(L) - 1:
if L[i] != L[i + 1]:
result.append(L[i])
i += 1
else:
i += 2
return result
assert get_good_array([1, 2, 2, 3, 4]) == [1, 3, 4]
assert get_good_array([1, 1, 2, 2, 3, 4]) == [3, 4]
assert get_good_array([0, 1, 1, 2, 2, 3, 4]) == [0, 3, 4]
assert get_good_array([1, 3, 4, 4]) == [1, 3]
assert get_good_array([1, 3, 4, 4, 5]) == [1, 3, 5]
You are missing a : at the end of the if statement, your code should look like the following
L=[]
n=int(input("Enter a num"))
for _ in range(n):
x=int(input())
L.append(x)
print(L)
for z in range(L):
if L[z]==L[z+1]:
L.remove(z)
L.remove(z+1)
print(L)
I guess using <list>.count() is quite intuitive approach. As following,
def deduplicate(l: list):
return [value for value in l if l.count(value) == 1]
assert deduplicate([2]) == [2]
assert deduplicate([2, 2]) == []
assert deduplicate([2, 2, 3]) == [3]
assert deduplicate([2, 2, 2]) == []
assert deduplicate([2, 2, 2, 3]) == [3]
This question already has answers here:
How to replicate array to specific length array
(4 answers)
Closed 2 years ago.
I need some kind of function or little tip for my problem.
So I got a list let's say
[1,2,3,4]
but I need this array to be longer with the same elements repeated so let's say I need an array of length 10 so it becomes:
[1,2,3,4,1,2,3,4,1,2]
So I need to extend the list with the same values as in the list in the same order
returnString = the array or string to return with extended elements
array = the basic array which needs to be extended
length = desired length
EDIT:
returnString = ""
array = list(array)
index = 0
while len(str(array)) != length:
if index <= length:
returnString += array[index]
index += 1
else:
toPut = index % length
returnString.append(array[toPut])
index += 1
return returnString
This is simple with itertools.cycle and itertools.islice:
from itertools import cycle, islice
input = [1, 2, 3, 4]
output = list(islice(cycle(input), 10))
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
You can use itertools.cycle to iterate repeatedly over the list, and take as many values as you want.
from itertools import cycle
lst = [1, 2, 3, 4]
myiter = cycle(lst)
print([next(myiter) for _ in range(10)])
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
You can also use it to extend the list (it doesn't matter if you append to the end while you are iterating over it, although removing items would not work).
from itertools import cycle
lst = [1, 2, 3, 4]
myiter = cycle(lst)
for _ in range(6):
lst.append(next(myiter))
print(lst)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
One way could be:
Iterate over the desired length - len(x_lst), So you have 10 - 4 = 6 (new elements to be added). Now since the list element should repeat, you can append the x_lst elements on the go by the indices (0,1,2,3,4,5).
x = [1,2,3,4]
length = 10
for i in range(length - len(x)):
x.append(x[i])
print(x)
OUTPUT:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
Try this:
n = 10
lst =[1,2,3,4]
new_lst = [lst[i%len(lst)] for i in range(n)]
print(new_lst)
Output:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
I will show a tip to you:
If you have this array [1,2,3,4] so you can create a separated newArray that get this value and fill the newArray with this repeated values.
How? Loop! I think for can do this to you, just point the array and newArray to it knows which it will fill.
NumOfValues = int(input("Number of Values: "))
List1 = [1,2,3,4]
List2 = []
Count = 0
while len(List2) < NumOfValues:
List2.append(List1[Count])
Count += 1
if Count > len(List1) - 1:
Count = 0
print(List2)
First multiply the list by the number of times it needs to be repeated. If that's not the desired length, extend it with the appropriate slice of the list.
old_len = len(original)
new_len = 10
result = original * new_len // old_len
if new_len % old_len != 0:
result += original[:new_len % old_len]
I have a list with 24 million elements and I want to increment count of each element iteratively and store the count in another list in faster way. For example, my list is:
a=['bike','bike','jeep','horse','horse','horse','flight','flight','cycle']
My expected output is
[1, 2, 1, 1, 2, 3, 1, 2, 1]
The code i used is
z=[]
for i in a:
z.append(a.count(i))
But my output is bit different
[2, 2, 1, 3, 3, 3, 2, 2, 1]
My order of this newly created list is also important and should be based on my list(a). Any help is really appreciated.
Based on your expected output, since you need the count of elements till that index of the list at which you are iterating at that point of time, the below code should work:
from collections import defaultdict
a=['bike','bike','jeep','horse','horse','horse','flight','flight','cycle']
a_dict = defaultdict(int)
a_output = []
for x in a:
a_dict[x] += 1
a_output.append(a_dict[x])
print(a_output)
Output:
[1, 2, 1, 1, 2, 3, 1, 2, 1]
Here is one solution -
a=['bike','bike','jeep','horse','horse','horse','flight','flight','cycle']
countArr = []
temp = {}
for i in a:
if i in temp:
temp[i]+=1
countArr.append(temp.get(i))
else:
temp[i] = 1
countArr.append(temp.get(i))
You could use a dictionary and a for loop to accomplish this:
counts = {}
a = ['bike','bike','jeep','horse','horse','horse','flight','flight','cycle']
z = []
for i in a:
if i in counts:
counts[i] += 1
else:
counts[i] = 1
z.append(counts[i])
print(z)
# [1, 2, 1, 1, 2, 3, 1, 2, 1]
You can also do this fun hacky thing with a list comprehension, which exploits the evaluation order of tuples and does essentially the same as the above for loop but condensed into one line:
counts = {}
z = [(counts.__setitem__(i, counts[i] + 1 if i in counts else 1), counts[i])[1] for i in a]
print(z)
# [1, 2, 1, 1, 2, 3, 1, 2, 1]
you can use sub-array count :
a=['bike','bike','jeep','horse','horse','horse','flight','flight','cycle']
z=[]
i = 0
while i < len(a):
#print(a[0:i])
#print(a[i])
z.append(a[0:i].count(a[i]) + 1)
i+= 1
print(z)
I am trying to check if a list has any consecutive repeating elements and then reorder it such that the repeats are avoided. If that is impossible, then return False. For example:
checkRepeat([1,2])
Out[61]: [1, 2]
checkRepeat([1,2,2])
Out[62]: [2, 1, 2]
checkRepeat([1,2,2,1,1])
Out[63]: [1, 2, 1, 2, 1]
checkRepeat([1,2,2,1,1,3,3,3,3])
Out[64]: [1, 3, 1, 3, 2, 1, 3, 2, 3]
checkRepeat([1,2,2,1,1,3,3,3,3,3])
Out[65]: [3, 1, 3, 2, 3, 1, 3, 1, 3, 2]
checkRepeat([1,2,2,1,1,3,3,3,3,3,3])
Out[66]: [3, 1, 3, 1, 3, 1, 3, 2, 3, 2, 3]
checkRepeat([1,2,2,1,1,3,3,3,3,3,3,3])
Out[67]: False
Here is what I have. Is there a more elegant solution?
from itertools import groupby
def checkRepeat(lst,maxIter=1000):
"""Returns a list that has no repeating elements. Will try for a max of 1000 iterations by default and return False if such a list can't be found"""
def hasRepeat(lst):
"""Returns true if there are any repeats"""
return len([x[0] for x in groupby(lst)]) < len(lst)
offset=numIter=0
while hasRepeat(lst) and numIter<maxIter:
for i,curElt in enumerate(lst):
try:
if lst[i]==lst[i+1]:
lst[i+1],lst[(i+offset) % len(lst)] = lst[(i+offset) % len(lst)],lst[i+1] #swap j+1 with j+offset. wrap around the list
except:
break
offset+=1
numIter+=1
if numIter==maxIter:
return False
else:
return lst
Here's the algorithm I alluded to in comments implemented, using the very useful collections.Counter class:
from collections import Counter
def check_repeat(sequence):
if not sequence:
return []
element_counts = Counter(sequence)
new_sequence = []
elements_chosen = 0
elements_needed = len(sequence)
previous_element_chosen = None
while elements_chosen < elements_needed:
candidates_needed = 1 if previous_element_chosen is None else 2
candidates = element_counts.most_common(candidates_needed)
candidate = (candidates[0] if
(len(candidates) < 2 or candidates[0][0] != previous_element_chosen)
else candidates[1])
if candidate[1] <= 0:
return False
else:
new_sequence.append(candidate[0])
element_counts[candidate[0]] -= 1
previous_element_chosen = candidate[0]
elements_chosen += 1
return new_sequence
This needs some refinement if None is a valid value in your sequence, or if you care about stability to any degree. If the elements of your sequence are not hashable, it won't work at all.
And that ternary candidate = ... assignment is probably clearer broken up a bit more.
You may try probability equation
Number which is repeating highest number of times must be always lessthen count of other numbers.
[1,2,2,1,1,3,3,3,3,3,3,3]
7< (3+2) false
[1,2,2,1,1,3,3,3,3,3,3]
6< (3+2) true
[1,2,2,1,1,3,3,3,3,3]
5< (3+3) true
code
from itertools import groupby
>>> a =[1,2,2,1,1,3,3,3,3,3]
>>> s = [len(list(group)) for key, group in groupby(a)]
>>> s
[1, 2, 2, 5]
>>> max(s) < (sum(s)-max(s))
True
I need to check if a list contains every element of another list in python. Not the set operation exactly, because in set distinct values are considered. How can I do it?
Sample:
a is the larger list, b is the smaller set
a = [1, 1, 2, 4], b = [1, 2, 3] -> False
a = [1, 1, 2, 3], b = [1, 2, 3] -> True
a = [1, 2, 4], b = [1, 2, 1] -> False // Because b has two 1s but a has only one.
I would like to request you to look at the third case carefully.
[N. B.] I know exactly how it can be done through hash map. But I want something less bulky.
A simple one-liner with Counter
def isin(a, b): return not (Counter(b) - Counter(a))
Demo:
>>> isin([1, 1, 2, 4], [1, 2, 3])
False
>>> isin([1, 1, 2, 3], [1, 2, 3])
True
>>> isin([1, 1, 2, 4], [1, 2, 1])
True
>>> isin([1, 2, 4], [1, 2, 1])
False
from collections import Counter
def is_contained(a,b):
aCount = Counter(a)
bCount = Counter(b)
return all(aCount[x] >= bCount[x] for x in bCount)
>>> is_contained([1, 1, 2, 4],[1, 2, 3])
False
>>> is_contained([1, 1, 2, 3], [1, 2, 3])
True
>>> is_contained([1, 2, 4], [1, 2, 1])
False
from collections import Counter
def is_contained(a, b):
aCount = Counter(a)
bCount = Counter(b)
# think of it as aCount >= bCount in set-operations
return aCount & bCount == bCount
I asked a similar question, which was closed with a reference to this one. The problem I have with these answers is that they all create a Counter object from the lists. Unless I am misunderstanding something, that is essentially creating a duplicate of both the full and the sub list. This is unimportant if both are small but if you're dealing with large lists, that's inefficient. I went with this:
def is_valid_sub(full_list, sub_list):
matched = []
for sub_item in sub_sublist:
for indx, full_item in enumerate(full_list):
if sub_item == full_item and indx not in matched:
matched.append(indx)
break
return len(matched) == len(sub_list)
Edit: Added more meaningful variable names
def contains(a,b):
for item in set(a):
if item in set(b):
print 'something or do something'