nested loop in list comprehension - python

I have a list of words in l that if any of it exists in the first index of each tuple in l2, remove the entire tuple.
my code:
l = ['hi', 'thanks', 'thank', 'bye', 'ok', 'yes', 'okay']
l2 = [('hi how are u', 'doing great'), ('looking for me', 'please hold')]
l3 = [k for k in l2 if not any(i in k[0] for i in l) ]
somehow the code does not work and i get back an empty list for l3.
I want
l3 = [('looking for me', 'please hold')]

Split k[0] to get a list of words:
[k for k in l2 if not any(i in k[0].split() for i in l)]
This way it checks if i matches a word exactly.
It could also be interpreted as if k[0] does not starts with any of l, then you can do this:
[k for k in l2 if not k[0].startswith(tuple(l))]

Sets make membership testing easy. Use a function to filter your list.
import operator
first = operator.itemgetter(0
l = ['hi', 'thanks', 'thank', 'bye', 'ok', 'yes', 'okay']
l2 = [('hi how are u', 'doing great'), ('looking for me', 'please hold')]
def foo(t, l = set(l)):
t = set(first(t).split())
return bool(l & t)
l3 = [thing for thing in l2 if not foo(thing)]

Related

Split The Second String of Every Element in a List into Multiple Strings

I am very very new to python so I'm still figuring out the basics.
I have a nested list with each element containing two strings like so:
mylist = [['Wowza', 'Here is a string'],['omg', 'yet another string']]
I would like to iterate through each element in mylist, and split the second string into multiple strings so it looks like:
mylist = [['wowza', 'Here', 'is', 'a', 'string'],['omg', 'yet', 'another', 'string']]
I have tried so many things, such as unzipping and
for elem in mylist:
mylist.append(elem)
NewList = [item[1].split(' ') for item in mylist]
print(NewList)
and even
for elem in mylist:
NewList = ' '.join(elem)
def Convert(string):
li = list(string.split(' '))
return li
print(Convert(NewList))
Which just gives me a variable that contains a bunch of lists
I know I'm way over complicating this, so any advice would be greatly appreciated
You can use list comprehension
mylist = [['Wowza', 'Here is a string'],['omg', 'yet another string']]
req_list = [[i[0]]+ i[1].split() for i in mylist]
# [['Wowza', 'Here', 'is', 'a', 'string'], ['omg', 'yet', 'another', 'string']]
I agree with #DeepakTripathi's list comprehension suggestion (+1) but I would structure it more descriptively:
>>> mylist = [['Wowza', 'Here is a string'], ['omg', 'yet another string']]
>>> newList = [[tag, *words.split()] for (tag, words) in mylist]
>>> print(newList)
[['Wowza', 'Here', 'is', 'a', 'string'], ['omg', 'yet', 'another', 'string']]
>>>
You can use the + operator on lists to combine them:
a = ['hi', 'multiple words here']
b = []
for i in a:
b += i.split()

function that returns elements in nested lists

So this is the exercise that I've been given:
def unflatten(ls):
"""returns elements in nested lists where the last element is None
ls = list with string elements
Examples:
>>> unflatten(['Hello', 'world'])
['Hello', ['world', None]]
>>> unflatten(['Hello'])
['Hello', None]
>>> unflatten(['No', 'more', 'cherries', 'please!'])
['No', ['more', ['cherries', ['please!', None]]]]
"""
"""write your code here"""
So I wrote this:
newls = []
x = 0
for x in range(len(ls)):
if x==0:
newls.append(ls[x])
elif x == len(ls)-1:
newls.append([ls[x], None])
else:
newls.append([ls[x], ])
print(newls)
which is correct only for a list of 2 elements
Could someone suggest any answers ??
Maybe I am overlooking things, but doesn't this simple recursive approach suffice:
def unflatten(ls):
if ls:
return [ls[0], unflatten(ls[1:])]
>>> unflatten(['Hello', 'world'])
['Hello', ['world', None]]
>>> unflatten(['Hello'])
['Hello', None]
>>> unflatten(['No', 'more', 'cherries', 'please!'])
['No', ['more', ['cherries', ['please!', None]]]]
There are many ways to dress up this horse in a more or less readable /explicit fashion, for a one-liner you can include a conditional expression:
def unflatten(ls):
if ls:
head, *tail = ls
return [head, unflatten(tail)]
return None # not necessary
def unflatten(ls):
return [ls[0], unflatten(ls[1:])] if ls else None
def unflatten(ls):
val = None
for word in reversed(ls):
val = [word, val]
return val
Or, even shorter:
from functools import reduce
def unflatten(ls):
return reduce(lambda v, w: [w, v], reversed(ls), None)
Here is a simple solution using recursion:
def unflatten(lst):
if not lst:
return None
return [lst[0], unflatten(lst[1:])]
>>> unflatten(['No', 'more', 'cherries', 'please!'])
['No', ['more', ['cherries', ['please!', None]]]]
The recursive solutions look better then doing it iteratively - buy you still can do that:
def unflatten(ls):
"""returns elements in nested lists where the last element is None"""
if isinstance(ls, list) and ls:
# create list with first element if ls is not empty
rv = [None if not ls else ls[0]]
# remember the outermost list that we return
rvv = rv
# add an empty list at end
rv.append([])
for e in ls[1:]:
# set rv to be the empty list at the end and add value
rv = rv[-1]
rv.append(e)
# add another empty list
rv.append([])
# replace empty list at end by None
rv[-1] = None
return rvv
else:
return ls # not a list - could raise an exception as well
print(unflatten(['Hello', 'world']))
print(['Hello', ['world', None]])
print(unflatten(['Hello']))
print(['Hello', None])
print(unflatten(['No', 'more', 'cherries', 'please!']))
print(['No', ['more', ['cherries', ['please!', None]]]])
Output:
['Hello', ['world', None]]
['Hello', ['world', None]]
['Hello', None]
['Hello', None]
['No', ['more', ['cherries', ['please!', None]]]]
['No', ['more', ['cherries', ['please!', None]]]]

How can I merge a list with a nested list?

I have two lists. The first one is a simple list with one entry:
l = [hello]
The second one is a nested list, with several thousand entries
i = [[world, hi],
[world, hi],
[world, hi],
[world, hi]]
Now I want to insert the entry from list l into the nested lists of i like this:
i = [[hello, world, hi],
[hello, world, hi],
[hello, world, hi],
[hello, world, hi]]
How can I do this?
You can use list comprehension to achieve that
i = [l+x for x in i]
Just use the insert method on each sublist in i.
for sublist in i:
sublist.insert(0, l[0])
If you don't want to modify i in place, and would prefer to build a new list, then
i = [[l[0], *sublist] for sublist in i]
simple: [[*l,*el] for el in i]
Output:
[['hello', 'world', 'hi'],
['hello', 'world', 'hi'],
['hello', 'world', 'hi'],
['hello', 'world', ' hi']]
I guess the benefits is that no matter how many elements you have in l, they will all be put in front of the stuff in i
Just add the element to the list you want
l = ["hello"]
i = [["world", "hi"],
["world", "hi"],
["world", "hi"],
["world", "hi"]]
x = []
for y in i:
x.append(l+y)
x
output:
[['hello', 'world', 'hi'],
['hello', 'world', 'hi'],
['hello', 'world', 'hi'],
['hello', 'world', 'hi']]
I believe something like this should do the trick:
l = ['hello']
i = [['world', 'hi'],
['world', 'hi'],
['world', 'hi'],
['world', 'hi']]
for j in i:
for k in l:
j = j.append(k)
I'm just iterating through your list i, nesting another for loop to iterate through the simpler list l (to account for the case whereby it has multiple elements), and simply appending each entry in l to the current list in i.

Conditional Merging of Lists

I'm trying to merge two lists based on the following rules:
The first element in list1 should be merged with the last element in list2, the second element in list1 should be merged with second last element in list2 and so on.
If an element in list1/list2 is None, then the corresponding element in the other list should be kept as it is in the merged list.
I feel I may have to use a linked list here, but I'm not sure. I'm trying to figure out the solution by looping over the lists, but I'm not able to figure out the logic here.
def merge_list(list1, list2):
merged_data=""
new_str=""
#write your logic here
for l1 in list1:
for l2 in list2[::-1]:
if l1 is None or l2 is None:
pass
else:
new_str = l1+l2
i=list2.index(l2)
print(new_str)
break
#return resultant_data
list1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
list2=['y','tor','e','eps','ay',None,'le','n']
merged_data=merge_list(list1,list2)
print(merged_data)
Expected Output:
“An apple a day keeps the doctor away”
You can use zip to iterate through two lists simultaneously:
def merge_list(lst1,lst2):
s = ''
for x, y in zip(lst1, lst2[::-1]):
if y and x:
s += x + y
elif x:
s += x
elif y:
s += y
s += ' '
return s[:-1]
list1 = ['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
list2 = ['y','tor','e','eps','ay',None,'le','n']
merged_data = merge_list(list1,list2)
print(merged_data)
# An apple a day keeps the doctor away
You can shorten this and use a list-comprehension, like below (but, I would prefer the other which is more readable):
def merge_list(lst1,lst2):
return ' '.join(x + y if x and y else x if x else y for x, y in zip(lst1, lst2[::-1]))
Assuming both lists have the same length
>>> list1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
>>> list2=['y','tor','e','eps','ay',None,'le','n']
>>> ' '.join([l1 + l2 if l1 and l2 else l1 if l1 and not l2 else l2 for l1, l2 in zip(list1, reversed(list2)) if l1 and l2])
'An apple a day keeps the doctor away'
Make sure the lists are in same length then just a zip is enough. But replace None value with '' (empty string)
["".join(row) for row in zip(list1, reversed(list2))]
=>
['An', 'apple', 'a', 'day', 'keeps', 'the', 'doctor', 'away']
First use list comprehensions to merge the two lists and then convert that list into string.
" ".join(str(x) for x in [list1[i]+list2[len(list2)-1-i] if list2[len(list2)-1-i] != None else list1[i] for i in range(len(list1))])
'An apple a day keeps the doctor away'
def fetch_index(list2, item_index):
x = list2[::-1]
return x[item_index]
def merge_list(list1, list2):
list_3 = []
#write your logic here
for l1 in list1:
l2 = fetch_index(list2, list1.index(l1))
if l1 is None and l2 is None:
pass
elif l1 is None:
list_3.append(l2)
elif l2 is None:
list_3.append(l1)
else:
list_3.append(l1+l2)
return(list_3)
list1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
list2=['y','tor','e','eps','ay',None,'le','n']
x = merge_list(list1,list2)
print ' '.join(i for i in x)
A longer version if you don't want to use zip
A short answer without using zip.
" ".join([list1[x]+[y if y is not None else '' for y in list2 ][::-1][x] for x in range(len(list1)-1)]
list1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
list2=['y','tor','e','eps','ay',None,'le','n']
a=list2.remove(None)
list2.insert(5,"")
list3 = [ str(x[0]) + x[1] for x in zip(list1, list2[::-1]) ]
print ' '.join(list3)
output:
An apple a day keeps the doctor away
l1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
l2=['y','tor','e','eps','ay',None,'le','n']
a=l2[::-1]
l3=[]
for i in range(len(l1)):
if(l1[i] is None or a[i] is None):
l3.append(l1[i])`enter code here`
else:
l3.append(l1[i]+a[i])
print(" ".join(l3))
def merge_list(list1, list2):
merged_data = ""
list3 = list1
for i in range(1, 2*len(list2) + 1,2): #Converting both lists in single list
list3.insert(i, list2[-1]) # Adding last elements of list2 at alternate to positions elements of list3
list2.pop() #Removing the last element from list2
list3 = ["" if i is None else i for i in list3] # Handling NoneType condition. If there is "None", convertted to ""
for i in range(0,len(list3),2):
word="".join(list3[i:i+2]) #joining the elements in set of two
merged_data=merged_data+word+" " #converting above word into one
return merged_data
list1=['A', 'app','a', 'd', 'ke', 'th', 'doc', 'awa']
list2=['y','tor','e','eps','ay',None,'le','n']
s=''
new=''
for i in list1:
for j in list2[::-1]:
if i==None:
i=''
elif j==None:
j=''
new=i+j
s=s+new+' '
list2.pop(-1)
break
print(s)

Python - How to match list elements by character to character

I have two list
List1 = ['hello','welcome','india','nation']
List2 = ['ind', 'nat','hellooo','welcomeeee']
i want to compare elements and print as below -
Output :
['india','nation','hello','welcome']
please suggest some optimized way.
I am having list with unspecified size in each, but it has one list elements matches another list elements, as random, i don't know the size of highest / longest possible match in any of the list.
You can use the Levenshtein distance to determine the closest match, so here is one implementation of Levenshtein:
def levenshteinDistance(s1, s2):
if len(s1) > len(s2):
s1, s2 = s2, s1
distances = range(len(s1) + 1)
for i2, c2 in enumerate(s2):
distances_ = [i2+1]
for i1, c1 in enumerate(s1):
if c1 == c2:
distances_.append(distances[i1])
else:
distances_.append(1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
distances = distances_
return distances[-1]
List1 = ['hello', 'welcome', 'india', 'nation']
List2 = ['ind', 'nat', 'helloooo', 'welcomeeeeee']
[min(zip(List1, [levenshteinDistance(j, i) for j in List1]), key=lambda x: x[1])[0] for i in List2]
#['india', 'nation', 'hello', 'welcome']
Similar to #AndreiDurnea's solution, you can also use a generator:
def comparer(L1, L2):
for i in L2:
for j in L1:
if (i in j) or (j in i):
yield j
List1 = ['hello','welcome','india','nation']
List2 = ['ind', 'nat','helloooo','welcomeeeeee']
res = list(comparer(List1, List2))
['india', 'nation', 'hello', 'welcome']
As per #pault's comment, itertools.product with a list comprehension may be more efficient than a generator:
from itertools import product
res = [j for i, j in product(List2, List1) if (i in j) or (j in i)]
List comprehension,
In [14]: [j for i in List2 for j in List1 if i in j or j in i]
Out[14]: ['india', 'nation', 'hello', 'welcome']
List1 = ['hello','welcome','india','nation']
List2 = ['ind', 'nat','helloooo','welcomeeeeee']
Rezult = []
for firstItem in List1:
for secondItem in List2:
if firstItem in secondItem or secondItem in firstItem:
Rezult.append(firstItem)
continue
print(Rezult)
the output for this is:
['hello', 'welcome', 'india', 'nation']
I would suggest to rename the variables:
list_1 = ['hello','welcome','india','nation']
list_2 = ['ind', 'nat','helloooo','welcomeeeeee']
rezult = []
for firstItem in list_1:
for secondItem in list_2:
if firstItem in secondItem or secondItem in firstItem:
rezult.append(firstItem)
print(rezult)

Categories