I have a nested list
elements = [['A', 'B'],['B','C'],['D','E','F']]
and I have list of indexes
ordered elements = ['A','B','C', 'D', 'E', 'F']
index= [308,302,303,405,506,609]
we know the elements and the indexes are matching by order
I want to recreate nested list by the indexes meaning the output would look like this:
out = [[308,302],[302,303],[405,506,609]]
You can use a mapping dict:
dmap = dict(zip(ordered_elements, index))
out = [[dmap[key] for key in lst] for lst in elements]
Output:
>>> out
[[308, 302], [302, 303], [405, 506, 609]]
>>> dmap
{'A': 308, 'B': 302, 'C': 303, 'D': 405, 'E': 506, 'F': 609}
prepare mapping (letter to index)
iterate over the elements and assign to output (using nested for/list comprehension)
e.g.
ordered_elements = ['A','B','C', 'D', 'E', 'F']
index= [308,302,303,405,506,609]
element_index_mapping = {letter:idx for e, letter in zip(ordered_elements, index)}
out = []
for letters in elements:
indices_for_letters = []
for letter in letters:
indices_for_letters.append(element_index_mapping.get(letter))
out.append(indices_for_letters)
I don't recommend this, but if you want it short, maybe you could try this:
result = [[index[ordered_elements.index(el_l1)] for el_l1 in el] for el in elements]
You could do it like this although there are no safety checks here:
elements = [['A', 'B'], ['B', 'C'], ['D', 'E', 'F']]
ordered_elements = ['A', 'B', 'C', 'D', 'E', 'F']
index = [308, 302, 303, 405, 506, 609]
out = [[index[ordered_elements.index(c)] for c in sl] for sl in elements]
print(out)
Output:
[[308, 302], [302, 303], [405, 506, 609]]
Related
element = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
index_list = [3,5,6,1,2,4,0]
result = [element[i] for i in index_list]
print(result)
this would eventually give me a ordered list based on the index list which would give
['d', 'f', 'g', 'b', 'c', 'e', 'a'].
How would you re-order this already re-ordered list back to its previous form which would be ['a', 'b', 'c', 'd', 'e', 'f', 'g']? I tried using the given index list again but it did not returned it back, but simply gave me a new list. Would there be any way I could still use the given index list to reorder the list back?
You can do the opposite:
reordered = [None] * len(result)
for index, e in zip(index_list, result):
reordered[index] = e
You can process index_list to do the reverse permutation:
index_list = [3,5,6,1,2,4,0]
reverse = [i for i, n in sorted(enumerate(index_list), key=lambda x: x[1])]
original = [result[i] for i in reverse]
something like this
print([a for a, b in sorted(zip(result, index_list), key=lambda x: x[1])])
how do I convert all the numerical strings, inside a list of list that contains both alphabetical, and numerical strings, into an integer?
My Output:
[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
Intended Output:
[[69, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420, 'F']]
Note that my code reads a CSV file. Thanks everyone
def get_csv_as_table(a, b):
s = False
import csv
with open(a) as csv_file:
file_reader = csv.reader(csv_file, delimiter=b)
member = list(file_reader)
print(member)
print ("Enter filename: ")
a = input()
print ("Enter the delimiter: ")
b = input()
get_csv_as_table(a, b)
You can use list comprehension to achieve this. The only minor downside to this is that you will be creating a new list for this instead of modifying the existing list.
my_list = [['69', 'Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
filtered_list = [
[int(item) if item.isdigit() else item for item in sub_list]
for sub_list in my_list
]
If you want to edit the list in-place, you can use traditional for-loop. The following code will edit the existing list without creating a new list. This could turn out to be useful in case you have a large list.
my_list = [['69', 'Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
for i in range(len(my_list)):
for j in range(len(my_list[i])):
if my_list[i][j].isdigit():
my_list[i][j] = int(my_list[i][j])
str.isdigit() checks if a given string is a number or not. An important note to keep in mind is that, it does not work for floating-point numbers, just integers. Once the condition passes, the item is converted to integer.
Yoy have to combine 2 levels of list-comprehension and use str.isdigit()
values = [
[int(val) if val.isdigit() else val for val in row]
for row in values
]
Try with 2-level list comprehension and int()+.isdigit() power combo in list comprehension ;-)
l=[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
l=[[int(y) if y.isdigit() else y for y in x] for x in l]
print(l)
Output:
[[69, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420, 'F']]
.isdigit() only works on string representation of pure integers, In case if you have floats too then replace '.' to nothing ;-)
l=[['69', ' Test', 'Results'], ['A', 'B', 'C'], ['D', '420', 'F']]
l=[[float(y) if y.replace('.','').isdigit() else y for y in x] for x in l]
print(l)
Output:
[[69.0, ' Test', 'Results'], ['A', 'B', 'C'], ['D', 420.0, 'F']]
As an example, right now I have a list of:
list = [[1276, 'c'], [910, 'b'], [819, 'o'], [759, 'z'], [699, 'l']]
and I would like to index this list for only a specific letter, for instance:
index = list.index('c')
As is, I realize that I'm going to get a ValueError, and I've learned that to make this work, I would need to index for the entire sublist.
index = list.index([1276,'c'])
Is there anyway I can work around having to index for the list as a whole, given that I don't currently know the integer value?
I hope this all makes sense, and if needed, I can certainly provide further clarification.
Thank you
If you know that the inner lists will only have two values, you could create your own function to get the first item that matches with next() and enumerate():
def get_index(lst, item):
return next((i for i, (_, x) in enumerate(lst) if x == item), None)
Which works like this:
print(get_index(lst, 'c')) # 0
print(get_index(lst, 'b')) # 1
print(get_index(lst, 'o')) # 2
print(get_index(lst, 'z')) # 3
print(get_index(lst, 'l')) # 4
print(get_index(lst, 'g')) # None
And returns None if an item was not found.
As suggested in the comments, a nicer solution would be to create a dictionary of index mappings:
def get_index(lst, item):
indices = {x: i for i, (_, x) in enumerate(lst)}
return indices.get(item)
Declaring a class whose instances are "equal" to any value can help.
class Any:
def __eq__(self, other):
return True
list = [[1276, 'c'], [910, 'b'], [819, 'o'], [759, 'z'], [699, 'l']]
index = list.index([Any(), 'c'])
print(index)
You could do it with a list comprehension that only returns the letter part of the tuple. The index will be the same.
index = [c for _,c in list].index('c')
Instead of directly iterating over the items in a list AKA for i in list, you can iterate an integer value over the length of the list AKA for i in range(len(list)).
Here is an example of how to obtain the index of the correct sublist.
list = [[1276, 'c'], [910, 'b'], [819, 'o'], [759, 'z'], [699, 'l']]
for i in range(len(list)):
if 'c' in list[i]:
index = i
break
Lookups using dictionaries are often faster, so you can build a dictionary, for example like this:
list_dct = dict([ [y, [i,x,y]] for i, (x, y) in enumerate(mylist)])
#=> {'c': [0, 1276, 'c'], 'b': [1, 910, 'b'], 'o': [2, 819, 'o'], 'z': [3, 759, 'z'], 'l': [4, 699, 'l']}
In this way you can access the index as:
list_dct['o'][0] #=> 2
If you can get rid of the index you can simply convert your list to a dict, then access by the letter to get the integer:
list_dct = dict([ [y,x] for i, (x, y) in enumerate(mylist)])
list_dct #=> {'c': 1276, 'b': 910, 'o': 819, 'z': 759, 'l': 699}
list_dct['c'] #=> 1276
Remember that duplicated keys in dictionaries are not allowed.
After reading so many title, I couldn't solved the problem below. Does anyone can help me please ?
For instance, I have 2 list (list_I and list_II) which is interrelated with each other.
list_I = [123, 453, 444, 555, 123, 444]
list_II = [A, A, B, C, A, B]
What I hope to get is:
New_list_I = [123, 453, 444, 555]
New_list_II = [A , A, B, C]
I use these two list as a body part of e-mail. That's why I need 2 separate (but on the other hand interrelated) list.
I'm able to send an e-mail right now. But because of the duplication problem it doesn't work how I want to.
P.S : I hope I explained the problem well but any question please don't hesitate to ask me.
Looks like a job very well suited for dict:
list_I = [123, 453, 444, 555, 123, 444]
list_II = ['A', 'A', 'B', 'C', 'A', 'B']
res = {}
for elem, elem2 in zip(list_I, list_II):
res[elem] = elem2
print(res)
OUTPUT:
{123: 'A', 453: 'A', 444: 'B', 555: 'C'}
And if you want the lists, you can separate the keys and values from the dict:
print([k for k,v in res.items()])
print([v for k,v in res.items()])
OUTPUT:
[123, 453, 444, 555]
['A', 'A', 'B', 'C']
list_I = [123, 453, 444, 555, 123, 444]
list_II = ['A', 'A', 'B', 'C', 'A', 'B']
New_list_I = []
New_list_II = []
for index, item in enumerate(list_I):
if item not in New_list_I:
New_list_I.append(item)
New_list_II.append(list_II[index])
print(New_list_I)
print(New_list_II)
OUTPUT:
[123, 453, 444, 555]
['A', 'A', 'B', 'C']
Finding common elements in list in python?
Imagine if i have a list like follows
[[a,b],[a,c],[b,c],[c,d],[e,f],[f,g]]
My output must be
[a,b,c,d]
[e,f,g]
How do i do it?
What i tried is like this
for i in range(0,len(fin3)):
for j in range(i+1,len(fin3)):
grop = []
grop = list(set(fin3[i]) & set(fin3[j]))
if len(grop)>0:
grop2 = []
grop2.append(link[i])
grop2.append(link[j])
grop3.append(grop2)
Thanks in advance...
I think you want something like:
data = [[1, 2], [2, 3], [4, 5]]
output = []
for item1, item2 in data:
for item_set in output:
if item1 in item_set or item2 in item_set:
item_set.update((item1, item2))
break
else:
output.append(set((item1, item2)))
output = map(list, output)
This gives:
output == [[1, 2, 3], [4, 5]]
If you want to find common elements even if lists are no adjacent and if the order in the result doesn't matter:
def condense_sets(sets):
result = []
for candidate in sets:
for current in result:
if candidate & current: # found overlap
current |= candidate # combine (merge sets)
# new items from candidate may create an overlap
# between current set and the remaining result sets
result = condense_sets(result) # merge such sets
break
else: # no common elements found (or result is empty)
result.append(candidate)
return result
Example:
>>> data = [['a','b'], ['a','c'], ['b','c'], ['c','d'], ['e','f'], ['f','g']]
>>> map(list, condense_sets(map(set, data)))
[['a', 'c', 'b', 'd'], ['e', 'g', 'f']]
See Replace list of list with “condensed” list of list while maintaining order.
As was noted in a comment above, it looks like you want to do set consolidation.
Here's a solution I adapted from code at the link in that comment above.
def consolidate(seq):
if len(seq) < 2:
return seq
result, tail = [seq[0]], consolidate(seq[1:])
for item in tail:
if result[0].intersection(item):
result[0].update(item)
else:
result.append(item)
return result
def main():
sets = [set(pair) for pair in [['a','b'],['a','c'],['b','c'],['c','d'],['e','f'],['f','g']]]
print("Input: {0}".format(sets))
result = consolidate(sets)
print("Result: {0}".format(result))
if __name__ == '__main__':
main()
Sample output:
Input: [set(['a', 'b']), set(['a', 'c']), set(['c', 'b']), set(['c', 'd']), set(['e', 'f']), set(['g', 'f'])]
Result: [set(['a', 'c', 'b', 'd']), set(['e', 'g', 'f'])]
Another approach, which looks about as (in)efficient -- O(n^2) where n = number of items. It's not quite elegant, but it's correct. The following function returns a set of (hashable) frozensets if you supply the value True for the named argument return_sets, otherwise it returns a list of lists (the default, as your question indicates that's what you really want):
def create_equivalence_classes(relation, return_sets=False):
eq_class = {}
for x, y in relation:
# Use tuples of x, y in case either is a string of length > 1 (iterable),
# and so that elements x, y can be noniterables such as ints.
eq_class_x = eq_class.get(x, frozenset( (x,) ))
eq_class_y = eq_class.get(y, frozenset( (y,) ))
join = eq_class_x.union(eq_class_y)
for u in eq_class_x:
eq_class[u] = join
for v in eq_class_y:
eq_class[v] = join
set_of_eq_classes = set(eq_class.values())
if return_sets:
return set_of_eq_classes
else:
return list(map(list, set_of_eq_classes))
Usage:
>>> data = [['a','b'], ['a','c'], ['b','c'], ['c','d'], ['e','f'], ['f','g']]
>>> print(create_equivalence_classes(data))
[['d', 'c', 'b', 'a'], ['g', 'f', 'e']]
>>> print(create_equivalence_classes(data, return_sets=False))
{frozenset({'d', 'c', 'b', 'a'}), frozenset({'g', 'f', 'e'})}
>>> data1 = [['aa','bb'], ['bb','cc'], ['bb','dd'], ['fff','ggg'], ['ggg','hhh']]
>>> print(create_equivalence_classes(data1))
[['bb', 'aa', 'dd', 'cc'], ['hhh', 'fff', 'ggg']]
>>> data2 = [[0,1], [2,3], [0,2], [16, 17], [21, 21], [18, 16]]
>>> print(create_equivalence_classes(data2))
[[21], [0, 1, 2, 3], [16, 17, 18]]