Related
#orignal list
list_one = [['a','b'],['a','c'],['b','c'],['b','a']]
li=[]
for i in list_one:
for j in list_one:
if i[0] == j[1] and j[0] == i[1]:
li.append([i,j])
print(li)
#[[['a', 'b'], ['b', 'a']], [['b', 'a'], ['a', 'b']]]
I need the output to be [a,b] only
the a and b can vary depending on the condition like a can be apple or anything
When considering a sublist, you only need to look for a duplicate in the queue of the list, beyond the current sublist. With minor changes to your code, you could do:
list_one = [['a','b'],['a','c'],['b','c'],['b','a']]
li=[]
for index, i in enumerate(list_one):
for index2 in range(index+1, len(list_one)):
j = list_one[index2]
if i[0] == j[1] and j[0] == i[1]:
li.append([i,j])
print(li)
# [[['a', 'b'], ['b', 'a']]]
It seems you are looking for items which contain letters that have not been seen before. The simplest way to do this is by building a cache.
cache = set() # will contain all individual letters that have been seen
li = []
for item in list_one:
if not any(letter in cache for letter in item):
li.append(item)
cache.update([letter for letter in item])
print(li)
[['a', 'b']]
One way could be:
Sort the list, find the duplicate nested.
#orignal list
data = [['a','b'],['a','c'],['b','c'],['b','a']]
seen = []
data = [sorted(x) for x in data]
data = [x if x in seen else seen.append(x) for x in data]
print([x for x in data if x])
OUTPUT:
[['a', 'b']]
I have a list of lists, and would like to keep the unique lists by ignoring one element of the list.
MWE:
my_list_of_lists = [['b','c','1','d'],['b','c','1','d'],['b','c','2','e']]
print(my_list_of_lists)
new_list_of_lists = []
for the_list in my_list_of_lists:
if the_list not in new_list_of_lists:
new_list_of_lists.append(the_list)
print(new_list_of_lists)
MWE Output:
[['b', 'c', '1', 'd'], ['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] # 1st print
[['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] # 2nd print
Question:
Is there a Pythonic way to remove duplicates as with the example above by ignoring a specific element within the inner list?
ie for my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']] should yield [['b','c','1','d'],['b','c','2','e']]
my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']]
# my_list_of_lists[0] and my_list_of_lists[1] are identical
# if my_list_of_lists[n][-2] is ignored
print(my_list_of_lists)
new_list_of_lists = []
for the_list in my_list_of_lists:
if the_list[ignore:-2] not in new_list_of_lists: #ignore the second last element when comparing
new_list_of_lists.append(the_list)
print(new_list_of_lists)
This is not "Pythonic" per se, but it is relatively short and gets the job done:
my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']]
print(my_list_of_lists)
new_list_of_lists = []
ignore = 2
for the_list in my_list_of_lists:
if all(
any(e != other_list[i]
for i, e in enumerate(the_list)
if i != ignore)
for other_list in new_list_of_lists
):
new_list_of_lists.append(the_list)
print(new_list_of_lists)
It outputs [['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] for the given input.
My question and your reply from the comments:
"ignoring a specific element" - Which one? The first? The largest? The one that's a digit? Some other rule? Your example input doesn't specify. – Heap Overflow
#HeapOverflow, I think a generic (non-specific) function would be best as other users in the future can integrate this generic function for their own use. – 3kstc
Doing that #GreenCloakGuy's style:
def unique(values, key):
return list({key(value): value for value in values}.values())
new_list_of_lists = unique(my_list_of_lists, lambda a: tuple(a[:2] + a[3:]))
A bit shorter:
def unique(values, key):
return list(dict(zip(map(key, values), values)).values())
Those take the last duplicate. If you want the first, you could use this:
def unique(values, key):
tmp = {}
for value in values:
tmp.setdefault(key(value), value)
return list(tmp.values())
The following approach
Creates a dict
where the values are the lists in the list-of-lists
and the corresponding keys are those lists without the indices you want to ignore, converted to tuples (since lists cannot be used as dict keys but tuples can)
Gets the dict's values, which should appear in order of insertion
Converts that to a list, and returns it
This preserves the later elements in the original list, as they overwrite earlier elements that are 'identical'.
def filter_unique(list_of_lists, indices_to_ignore):
return list({
tuple(elem for idx, elem in enumerate(lst) if idx not in indices_to_ignore) : lst
for lst in list_of_lists
}.values())
mlol = [['b','c','1','d'],['b','c','3','d'],['b','c','2','d']]
print(filter_unique(mlol, [2]))
# [['b', 'c', '3', 'd'], ['b', 'c', '2', 'e']]
print(filter_unique(mlol, [3]))
# [['b', 'c', '1', 'd'], ['b', 'c', '3', 'd'], ['b', 'c', '2', 'e']]
That's a one-liner, abusing a dict comprehension. A multi-line version might look like this:
def filter_unique(list_of_lists, indices_to_ignore):
dct = {}
for lst in list_of_lists:
key = []
for idx, elem in enumerate(lst):
if idx not in indices_to_ignore:
key.append(elem)
dct[tuple(key)] = lst
return list(dct.values())
Im trying to add a prefix to a list of strings in Python. The list of strings may contain multiple levels of nested lists.
Is there a way to loop through this list (and its nested lists), while keeping the structure?
nested for-loops became unreadable very quick, and did not seem to be the right approach..
list = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee']]]
for i in list:
if isinstance(i, list):
for a in i:
a = prefix + a
#add more layers of for loops
else:
i = prefix + i
desired outcome:
prefix = "#"
newlist = ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
Thanks in advance!
You could write a simple recursive function
def apply_prefix(l, prefix):
# Base Case
if isinstance(l, str):
return prefix + l
# Recursive Case
else:
return [apply_prefix(i, prefix) for i in l]
l = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee',]]]
print(apply_prefix(l, "#"))
# ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
This will use recursion:
a = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee',]]]
def insert_symbol(structure, symbol='#'):
if isinstance(structure, list):
return [insert_symbol(sub_structure) for sub_structure in structure]
else:
return symbol + structure
print(insert_symbol(a))
>>> ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
You can use a recursive code like this!, Try it, and if you have questions you can ask me
def add_prefix(input_list):
changed_list = []
for elem in input_list:
if isinstance(elem, list):
elem = add_prefix(elem)
changed_list.append(elem)
else:
elem = "#" + elem
changed_list.append(elem)
return changed_list
Maybe you can use a function to do it recursively.
list_example = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee']]]
def add_prefix(p_list, prefix):
for idx in range(len(p_list)):
if isinstance(p_list[idx], list):
p_list[idx] = add_prefix(p_list[idx], prefix)
else:
p_list[idx] = prefix + p_list[idx]
return p_list
add_prefix(list_example, '#')
edit: I see now someone has posted the almost same thing.
btw. it is considered bad practice to name a list list, since it is also a typename in python. Might result in unwanted behaviour
I am searching through a list like this:
my_list = [['a','b'],['b','c'],['a','x'],['f','r']]
and I want to see which elements come with 'a'. So first I have to find lists in which 'a' occurs. Then get access to the other element of the list. I do this by abs(pair.index('a')-1)
for pair in my_list:
if 'a' in pair:
print( pair[abs(pair.index('a')-1)] )
Is there any better pythonic way to do that?
Something like: pair.index(not 'a') maybe?
UPDATE:
Maybe it is good to point out that 'a' is not necessarily the first element.
in my case, ['a','a'] doesn't happen, but generally maybe it's good to choose a solution which handles this situation too
Are you looking for elements that accompany a? If so, a simple list comprehension will do:
In [110]: [x for x in my_list if 'a' in x]
Out[110]: [['a', 'b'], ['a', 'x']]
If you just want the elements and not the pairs, how about getting rid of a before printing:
In [112]: [(set(x) - {'a'}).pop() for x in my_list if 'a' in x]
Out[112]: ['b', 'x']
I use a set because a could either be the first or second element in the pair.
If I understand your question correctly, the following should work:
my_list = filter(
lambda e: 'a' not in e,
my_list
)
Note that in python 3, this returns a filter object instance. You may want to wrap the code in a list() command to get a list instance instead.
That technique works ok here, but it may be more efficient, and slightly more readable, to do it using sets. Here's one way to do that.
def paired_with(seq, ch):
chset = set(ch)
return [(set(pair) - chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r']]
print(paired_with(my_list, 'a'))
output
['b', 'x']
If you want to do lots of tests on the same list, it would be more efficient to build a list of sets.
def paired_with(seq, ch):
chset = set(ch)
return [(pair - chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r']]
my_sets = [set(u) for u in my_list]
print(my_sets)
print(paired_with(my_sets, 'a'))
output
[{'b', 'a'}, {'c', 'b'}, {'x', 'a'}, {'r', 'f'}]
['b', 'x']
This will fail if there's a pair like ['a', 'a'], but we can easily fix that:
def paired_with(seq, ch):
chset = set(ch)
return [(pair - chset or chset).pop() for pair in seq if ch in pair]
my_list = [['a','b'], ['b','c'], ['x','a'], ['f','r'], ['a', 'a']]
my_sets = [set(u) for u in my_list]
print(paired_with(my_sets, 'a'))
output
['b', 'x', 'a']
I have a nested list:
my_list = ['a','b','c','dog', ['pig','cat'], 'd']
and a dict:
my_dict = {'dog':'c','pig':'a','cat':'d'}
I would like to use the dict, such that I get a list:
new_list = ['a', 'b', 'c', 'c', ['a', 'd'], 'd']
I've tried something like:
new_list = []
for idx1, item1 in enumerate(my_list):
for idx2, item2 in enumerate(item1):
new_list[idx1][idx2] = my_dict[item2]
but I get an error when item2 does not exist in the dict. Is there a better way to do this?
You could write a simple recursive function that uses list comprehension to generate the result. If item on your list is a list then recurse, otherwise use dict.get with default parameter to convert the item:
my_list = ['a','b','c','dog', ['pig','cat'], 'd']
my_dict = {'dog':'c','pig':'a','cat':'d'}
def convert(l, d):
return [convert(x, d) if isinstance(x, list) else d.get(x, x) for x in l]
print(convert(my_list, my_dict))
Output:
['a', 'b', 'c', 'c', ['a', 'd'], 'd']
You look l ike you're trying to substitute into a nested list. Try this function this will recursively swap the values for you:
def replace_vals(_list, my_dict):
new_list = []
for item in _list:
if isinstance(item, list):
new_list.append(replace_vals(item, my_dict))
elif item in my_dict:
new_list.append(my_dict.get(item))
else:
new_list.append(item)
return new_list
print replace_vals(my_list, my_dict)
my_list = ['a','b','c','dog', ['pig','cat'], 'd']
my_dict = {'dog':'c','pig':'a','cat':'d'}
def replace(item):
if item in my_dict:
return my_dict[item]
else:
return item
new_list=[];
for item in my_list:
if isinstance(item,list):
temp_list=[]
for subitem in item:
temp_list.append(replace(subitem))
new_list.append(temp_list)
else:
new_list.append(replace(item))
print new_list
This piece of code will not work if the list inside my_list is nested in itself.