Go through all possibilities Python - python

I have two lists, let's say:
l1 = ['c', 'o', 'k', 'e']
l2 = ['a', 'b', 'c', 'd']
I would like to create a loop, that would check if each letter in l1 is in l2 (if that's the case I would get " ") or if it's there and on the same position (in that case I would get "Y").
I started with this code (unfortunately I failed). Could you please advise what's missing?
for i in l1:
for j in range(0,4):
if l1[j] == l2[j]:
v = "Y"
elif i in l2:
v = "."
else:
v = "N"
text = "".join(v)
Which those lists in the example, I would assume to get:
text = .NNN
I understand that this might be an easy question, but I'm a beginner and it's driving me crazy :)

Looking at your code, you can use zip() to iterate over the two lists simultaneously. Also use str.join after the loop:
l1 = ["c", "o", "k", "e"]
l2 = ["a", "b", "c", "d"]
out = []
for a, b in zip(l1, l2):
if a == b:
out.append("Y")
elif a in l2:
out.append(".")
else:
out.append("N")
print("".join(out))
Prints:
.NNN

l1 = ['c', 'o', 'k', 'e']
l2 = ['a', 'b', 'c', 'd']
text = ""
for i in l1:
if i in l2:
v = "."
else:
v = "N"
text += v
print(text)
First we define text="" so that we can just append. Then we loop all the letters in l1. We then check if that letter is in l2. if it is we add '.' to text if its not we add N. And finally we print the text

You can do something like:
ans = ""
for i, val in enumerate(l1):
if l2[i] == val:
ans += "Y"
elif val in l2:
ans += "."
else
ans += "N"

You don't have to loop trough the second array with the operations you are performing. You can simplify your code like this.
l1 = ['c', 'o', 'k', 'e']
l2 = ['a', 'b', 'c', 'd']
text = ""
for i in range(len(l1)):
if l1[i] == l2[i]:
text += "Y"
elif l1[i] in l2:
text += "."
else:
text += "N"
print(text)
Looping twice is not needed and therefore not the most efficient solution to your problem.

Use python sets.
Simple ./N check
l1 = ['c', 'o', 'k', 'e']
l2 = ['a', 'b', 'c', 'd']
S = set(l2)
out = ''.join('.' if x in S else 'N' for x in l1)
output: .NNN
more complex ./Y/N check:
l1 = ['c', 'o', 'k', 'e', 'z']
l2 = ['a', 'b', 'c', 'd', 'z']
S = set(l2)
out = ''.join(('Y' if l2[i]==x else '.') if x in S else 'N'
for i, x in enumerate(l1))
output: .NNNY

l1 = ['c', 'o', 'k', 'e']
l2 = ['a', 'b', 'c', 'd']
text = ""
for char in l1:
if char in l2:
index = l1.index(char)
if char == l2[index]:
v = "Y"
else:
v = "."
else:
v = "N"
text += v
print(text)

Related

Break a first for loop within a second for loop

I have almost completed a script to compare two lists (listA and listB).
The script should return the similar values between the lists, that are following each others, and with single occurrences.
listA=['b', 'c', 'd', 'c', 'c']
listB=['a', 'b', 'c']
def ordered_matches(list1, list2):
list = []
len1 = len(list1)
len2 = len(list2)
start_range = 0
for f1 in range(len1):
for f2 in range(start_range, len2):
if list1[f1] == list2[f2] and f2 != len2:
list.append(list1[f1]);
start_range = f2;
break
elif list1[f1] == list2[f2] and f2 == len2:
list.append(list1[f1]);
continue
break
return list
ordered_matches(listA, listB)
Here are examples of input/output expected:
listA=['a', 'b', 'c', 'd', 'e']
listB=['d', 'e', 'f', 'g', 'h']
output=['d','e']
listA=['a', 'b', 'c', 'd', 'e']
listB=['h', 'd', 'g', 'd', 'f']
output=['d']
listA=['b', 'a', 'c', 'a', 'e']
listB=['b', 'a', 'e', 'b', 'e']
output=['b', 'a', 'e']
To reach this result, the first for loop of the script should be broken.
But unfortunately, I can't manage to break the first for loop within the second for loop.
Would you have any advice to do it?
I think I have found an answer that does not require to break the outer loop. The main question of this topic is not addressed, but at least the script seems to work.
def ordered_matches(list1, list2):
list = []
len1 = len(list1)
len2 = len(list2)
start_range = 0
for f1 in range(len1):
for f2 in range(start_range, len2):
if list1[f1] == list2[f2]:
list.append(list1[f1]);
start_range = f2+1;
break
return list
However, it is noticeable that the position of the inputs in the command can change the outputs.

I need to return list 1 index and list 2 index, when list 1 matches with list 2

I need to return the index in list 1 and list 2, when list 1 matches with list 2
I have a code like:
def list_contains(List1, List2):
id1=0
id2=0
# Iterate in the 1st list
for idx, m in enumerate(List1):
# Iterate in the 2nd list
for idx2, n in enumerate(List2):
# if there is a match
if m != n:
None
else:
id1 = idx
id2 = idx2
return (id1,id2)
List1 = ['a', 'e', 'i', 'o', 'u']
List2 = ['s','a', 'b', 'c', 'd', 'e']
print(list_contains(List1, List2))
what to change here , so i can get all the matching indexes...
Try adding the matching indexes to a list. Create empty list and add all matching indexes to it. finally return the list.
res = []
# Iterate in the 1st list
for idx, m in enumerate(List1):
# Iterate in the 2nd list
for idx2, n in enumerate(List2):
# if there is a match
if m != n:
None
else:
res.append((idx, idx2))
or You can use yield
for idx, m in enumerate(List1):
# Iterate in the 2nd list
for idx2, n in enumerate(List2):
# if there is a match
if m != n:
None
else:
yield (idx, idx2)
then convert the result to list
print(list(list_contains(List1, List2)))
Efficient solution would be using a dictionary. Create dictionary with List2 where list element is key and index is value. This will work if List2 has no duplicates.
def list_contains(List1, List2):
d = {x: idx for idx, x in enumerate(List2)}
return [(idx, d[y]) for idx, y in enumerate(List1) if y in d]
basically this:
for each in List1:
if each in List2:
id1.append(List1.index(each))
id2.append(List2.index(each))
return (id1,id2)
oh ok, this then:
List1 = ['a', 'e', 'i', 'o', 'u']
List2 = ['s','a', 'b', 'c', 'd', 'e']
matches = []
for each in List1:
if each in List2:
matches.append(str(List1.index(each)) + str(List2.index(each)))
print(matches)
this will provide you the indexes in each list
List1 = ['a', 'e', 'i', 'o', 'u']
List2 = ['s', 'a', 'b', 'c', 'd', 'e']
List3 = []
for num1, l1 in enumerate(List1):
for num2, l2 in enumerate(List2):
if l1 == l2:
List3.append((num1, num2))
print(List3)
the output will be:
[(0, 1), (1, 5)]
To get all matches you are very close to what you want to do. Rather than do it externally I would suggest you do this
List1 = ['a', 'e', 'i', 'o', 'u']
List2 = ['s','a', 'b', 'c', 'd', 'e']
List3 = []
for x in List2:
for y in range(len(List1)):
if x = List1[y]
List3.append(y)
print(List3)
This will simply loop through each value of the second List and compare it to all the elements of the first list. If they match it will then store the index of the first list that matched. This is then outputted at the end.
I have assumed as per your example that you want the index based off of the first list.
IF you want to get both indexes then you can modify it as such
List1 = ['a', 'e', 'i', 'o', 'u']
List2 = ['s','a', 'b', 'c', 'd', 'e']
List3 = []
for x in range(len(List2)):
for y in range(len(List1)):
if List2[x] = List1[y]
List3.append(List2[x] + ',' + List1[y])
print(List3)
This will result in string comma separated answers. If you do not want this then simply remove the +','+ and put in a ,
You can try this approach to return/yield the index values when the values match for both List1 and List2:
def list_contains(List1, List2):
for index, val in enumerate(zip(List1, List2)):
if val[0]==val[1]:
yield index
yield gives you a generator object. Iterate over the generator object like any other iterator to get the values:
matching_index = list_contains(list1, list2)
for index_values in matching_index:
print(index_values)

How to create a list which only adds letters that are unique to adjacent indices in python?

I have created a function which randomly generates a list of the letters "a", "b", "c", and "d". I would like to create a new list which is the same as the first list but with any letters/items which are the same as the previous letter/item removed. Where I am having problems is referring to the previous letter in the list.
For example, if :
letterlist = ['a','a','a','b','b','a,',b']
then the output should be,
nondupelist = ['a','b','a','b']
The problem is that nodupeletterlist is the same as letterlist - meaning it's not removing items which are the same as the last - because I am getting the function to refer to the previous item in letterlist wrong. I have tried using index and enumerate, but I am obviously using them wrong because I'm not getting the correct results. Below is my current attempt.
import random
def rdmlist(letterlist, nodupeletterlist):
for item in range(20):
rng = random.random()
if rng < 0.25:
letterlist.append("a")
elif 0.25 <= rng and rng < 0.5:
letterlist.append("b")
elif 0.5 <= rng and rng < 0.75:
letterlist.append("c")
else:
letterlist.append("d")
for letter in letterlist:
if letter != letterlist[letterlist.index(letter)-1]:
nodupeletterlist.append(letter)
else:
pass
return
letterlist1 = []
nodupeletterlist1 = []
rdmlist(letterlist1, nodupeletterlist1)
EDIT:
This is what I ended up using. I used this solution simply because I understand how it works. The answers below may provide more succinct or pythonic solutions.
for index, letter in enumerate(letterlist, start=0):
if 0 == index:
nodupeletterlist.append(letter)
else:
pass
for index, letter in enumerate(letterlist[1:], start = 1):
if letter != letterlist[index-1]:
nodupeletterlist.append(letter)
else:
pass
for i, letter in enumerate(([None]+letterlist)[1:], 1):
if letter != letterlist[i-1]:
nodupeletterlist.append(letter)
You can use itertools.groupby:
import itertools
nodupeletterlist = [k for k, _ in itertools.groupby(letterlist)]
Solution without using itertools, as requested in the comments:
def nodupe(letters):
if not letters:
return []
r = [letters[0]]
for ch in letters[1:]:
if ch != r[-1]:
r.append(ch)
return r
nodupeletterlist = nodupe(letterlist)
A fixed version of the proposed "working solution":
def nodupe(letters):
if not letters:
return []
r = [letters[0]]
r += [l for i, l in enumerate(letters[1:]) if l != letters[i]]
return r
nodupeletterlist = nodupe(letterlist)
You can also simplify your random generator a bit, by using random.choices:
import random
chars = 'abcd'
letterlist = random.choices(chars, k=20)
or by using random.randint:
import random
start, end = ord('a'), ord('d')
letterlist = [chr(random.randint(start, end)) for _ in range(20)]
Here's what I came up with. Using random.choices() would be better than what I have below, but same idea. doesn't involve itertools
>>> li_1 = [random.choice("abcdefg") for i in range(20)]
>>> li_1
['c', 'e', 'e', 'g', 'b', 'd', 'b', 'g', 'd', 'c', 'e', 'g', 'e', 'c', 'd',
'e', 'e', 'f', 'd', 'd']
>>>
>>> li_2 = [li_1[i] for i in range(len(li_1))
... if not i or i and li_1[i - 1] != li_1[i]]
>>> li_2
['c', 'e', 'g', 'b', 'd', 'b', 'g', 'd', 'c', 'e', 'g', 'e', 'c',
'd', 'e', 'f', 'd']
The problem with the way that you are using letterlist.index(letter)-1 is that list.index(arg) returns the the index of the first occurrence of arg in list, in this case the letter. This means that if you have list = ["a", "b", "a"] and you run list.index("a") it will always return 0.
A way to do what you intend to (removing consecutive repetitions of letters) would be:
nodupeletterlist.append(letterlist[0])
for idx in range(1, len(letterlist)):
if letterlist[idx] != letterlist[idx-1]:
nodupeletterlist.append(letterlist[idx])
Do This:
L1 = ['a','a','a','b','b','c','d']
L2 = []
L2.append(L1[0])
for i in range(1,len(L1)):
if L1[i] != L1[i-1]:
L2.append(L1[i])
set() will create a set with only unique values,then the list() will convert it back to a a list containing values without any repetition.
I hope this helps...

Join consecutive pairs of strings in a list if they meet a condition

Given two lists:
list1 = ["a","b","c","d","e","f","b","c","b","d","f","c","b","e"]
list2 = ["b","c"]
with the assumption len(list2) == 2,
I was wondering how to get an output like this:
['a', 'bc', 'd', 'e', 'f', 'bc', 'b', 'd', 'f', 'c', 'b', 'e']
Essentially any instance of list2 within list1 (in that order), should concatenate in the original list1 and output (after checking all possibilities).
What I tried so far:
l = len(list1)
for i in range(0,l-1):
if list1[i] == list2[0]:
if list1[i+1] == list2[1]:
a = i
b = i+1
list1[a:b+1] = [''.join(list1[a:b+1])]
l = l - 1
print(list1)
But keep getting an error:
if list1[i] == list2[0]: IndexError: list index out of range
Try this, should work for any length of list2 :
split_pattern = ''.join(list2)
chunks = ''.join(list1).split(split_pattern)
result = list(chunks[0])
for c in chunks[1:] :
result.append( split_pattern )
result.extend( list(c) )
checking the result :
>>> result
['a', 'bc', 'd', 'e', 'f', 'bc', 'b', 'd', 'f', 'c', 'b', 'e']
Assuming the question is why you are getting an error, this line
list1[a:b+1] = [''.join(list1[a:b+1])]
modifies list1, and actually makes it shorter. So when you are looping on a range that is the length of list 1, making the list shorter means that the loop counter i will eventually be out of range, because the elements of the list you intended to find with the index are gone.
You also need to remember that lists are indexed from 0 to n - 1, where n is the length of the list, so this statement
if list1[i+1] == list2[1]:
looks like it really should be
if list[i] == list2[0]:
Also the outer loop is based on range(0, l - 1) means that it will loop through every index except the last one. So unless you really want to avoid looking at the last element of the list, which I don't think you do based on your requirements, you would use range(l), which produces indexes from 0 to l - 1.
This is one approach using list slicing.
Ex:
list1 = ["a","b","c","d","e","f","b","c","b","d","f","c","b","e"]
list2 = ["b","c"]
l = len(list2)
result = []
skip = 0
for i, v in enumerate(list1):
if skip:
skip -= 1
continue
if list1[i:l+i] == list2: #Check for sub-element
result.append("".join(list2))
skip = l-1 #Skip flag
else:
result.append(v)
print(result)
Output:
['a', 'bc', 'd', 'e', 'f', 'bc', 'b', 'd', 'f', 'c', 'b', 'e']
Try this:
list1 = ["a","b","c","d","e","f","b","c","b","d","f","c","b","e"]
list2 = ["b","c"]
l = len(list1)
new_list = []
last_merge = False
for i in range(0,l):
# match list1 index i element with list2 first element
if list1[i] == list2[0]:
# match list1 index i+1 element with list2 second element
if i+1 <= l and list1[i+1] == list2[1]:
# merge and append list1 index i and i+1 element
new_list.append(list1[i]+list1[i+1])
# mark merge as true
last_merge = True
else:
# append list1 index i element
new_list.append(list1[i])
else:
# check list index i element is merge with last element then mark last_merge as False and continue iterate list
if last_merge is True:
last_merge = False
continue
# append list1 index i element
new_list.append(list1[i])
print(new_list)
O/P:
['a', 'bc', 'd', 'e', 'f', 'bc', 'b', 'd', 'f', 'c', 'b', 'e']
def new_f(l1,l2):
for i,j in zip(l2,l1):
if i!=j:
return False
return True
def func(l1,l2):
res=[]
index = 0
l2_string = ''.join(l2)
while index<len(l1):
if l1[index]==l2[0] and new_f(l1[index:index+len(l2)], l2): # if first element found then checck compare with list2
# compare with list2 if elemnt match with first elment of list2
res.append(l2_string)
index+=len(l2)
else:
res.append(l1[index])
index+=1
return res
list1 = ["a", "b","b", "c", "d", "e", "f", "b", "c", "b", "d", "f", "c", "b", "e"]
list2 = ["b", "c"]
result= func(list1,list2)
print(result)
output
['a', 'b', 'bc', 'e', 'f', 'bc', 'd', 'f', 'c', 'b', 'e']
I'd like to suggest this method which returns a generator:
def join_if_ref(main_list, ref_list):
n, s = len(ref_list), "".join(ref_list)
i, size = 0, len(main_list)
while i < size-n+1:
j = "".join(main_list[i:i+n])
if j == s:
yield j
i += n - 1
else:
yield main_list[i]
if i < size: i += 1
for k in range(size-i):
yield(main_list[k+i])
In this case:
list1 = ["a","b","c","d","e","f","b","c","b","d","f","c","b","c","d","k","s"]
list2 = ["b","c","d"]
It returns:
res = join_if_ref(list1, list2)
print(list(res))
#=> ['a', 'bcd', 'e', 'f', 'b', 'c', 'b', 'd', 'f', 'c', 'bcd', 'k', 's']
Version with arbitrary list2 length:
def sublist_concatenate(list1, list2):
N = len(list2)
fullset = ''.join(list2)
outlist = []
i = 0 # counts the number of matches so far
for el in list1:
if el == list2[i]: # hold matching elements so far
i += 1
if i == N: # we have matched N times, so we have the whole set
outlist.append(fullset)
i = 0
else: # not a match for the next position
outlist += list2[0:i] # add all previously-passed elements
# check whether it is a match for the first position though
if el == list2[0]:
i = 1
else:
outlist.append(el)
i = 0
return outlist
l1 = ["a", "b", "b", "c", "d", "e", "f",
"b", "c", "b", "d", "f", "c", "b", "e"]
l2 = ["b", "c"]
print sublist_concatenate(l1, l2)
# ['a', 'b', 'bc', 'd', 'e', 'f', 'bc', 'b', 'd', 'f', 'c', 'b', 'e']
EDIT: code fixed per comments, adding the if el == list2[0] branch.

How can I reverse a section of a list using a loop in Python?

I'm in need of a little help reversing a section of a list in Python using a loop.
I have a list: mylist = ['a', 'b', 'c', 'd', 'e', 'f']
Also have an index number, this number will tell where to start the reversing. For example, if the reverse-index number is 3, it needs to be something like this: ['d', 'c', 'b', 'a', 'e', 'f']
What I currently have:
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = []
for item in range( len(list1) ):
n_list.append( (list1[(reverse_index - 1) - item]) )
item += 1
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print( list_section_reverse(mylist, 3) )
Which returns ['c', 'b', 'a', 'f', 'e', 'd']
How can I alter my code, so that it prints out ['d', 'c', 'b', 'a', 'e', 'f']?
You can simply use:
def list_section_reverse(list1, reverse_index):
return list(reversed(list1[:reverse_index+1])) + list1[reverse_index+1:]
Edit: The problem with your existing solution is that you keep reversing after reverse_index. If you have to use a loop, try this:
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = list1[:]
for i in range(reverse_index + 1):
n_list[i] = list1[-i-reverse_index]
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print(list_section_reverse(mylist, 3))
The pythonic solution:
list1[reverse_index::-1] + list1[reverse_index+1:]
Now, that's not using loops like you asked. Well, not explicitly... Instead we can break down the above into its constituent for loops.
def list_section_reverse(list1, reverse_index):
if reverse_index < 0 or reversed_index >= len(list1):
raise ValueError("reverse index out of range")
reversed_part = []
for i in range(reverse_index, -1, -1): # like for i in [n, n-1, ..., 1, 0]
reversed_part.append(list1[i]
normal_part = []
for i in range(reverse_index + 1, len(list1)):
normal_part.append(list1[i])
return reversed_part + normal_part
Is it allowed to make a copy of the list?
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = [ element for element in list1 ]
for item in range( reverse_index + 1 ):
n_list[ item ] = list1[ reverse_index - item ]
item += 1
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print(list_section_reverse(mylist, 3))
Outs:
In function reverse()
['d', 'c', 'b', 'a', 'e', 'f']
You can modify the list inplace using a slice.
mylist[:4] = mylist[:4][::-1]
You can try this. This makes use of no slicing, and can use either a while loop or for loop.
def reversed_list(my_list, index):
result = []
list_copy = my_list.copy()
i = 0
while i < index+1:
result.append(my_list[i])
list_copy.remove(my_list[i])
i+=1
result.reverse()
return result + list_copy
Or with a for loop
def reversed_list(my_list, index):
result = []
list_copy = my_list.copy()
for i in range(len(my_list)):
if i < index + 1:
result.append(my_list[i])
list_copy.remove(my_list[i])
result.reverse()
return result + list_copy

Categories