Sorting a 2D list alphabetically? - python

I have a 2D list such as this:
lst = [['c', 'd', 'b'], ['d', 'c', 'a'], ['b', 'a', 'c']]
I would first like to sort each list within the list alphabetically like this:
lst = [['b', 'c', 'd'], ['a', 'c', 'd'], ['a', 'b', 'c']]
And finally, I would like to sort the whole list alphabetically which takes into account each element in a sublist:
lst = [['a', 'b', 'c'], ['a', 'c', 'd'], ['b', 'c', 'd']]
What would be the fastest way to achieve this? Thank you.

The fastest way in general should be just as you described it:
for sublist in lst:
sublist.sort()
lst.sort()
Alternatively, if you want to do it out of place:
new_lst = [sorted(sublist) for sublist in lst]
new_lst.sort()

Related

how to remove an item in a list of list of string using index in python

input:
letters = [['a', 'b', 'c'], ['a', 'b', 'c']]
row= 0
column=0
output
[['b', 'c'], ['a', 'b', 'c']]
I tried to do this:
letters[0].remove(0)
but it gives me a value error, while when I use pop like this:
letters[0].pop(0)
it does what I need but the problem with pop is that it returns me something while I just need the item to be removed
letters = [['a', 'b', 'c'], ['a', 'b', 'c']]
del list1[0][0]
use the del keyword
list.remove() removes an item by value, not by index. So letters[0].remove('b') would work.
Simply deleting a single element with the same syntax, you could address it in any other statement is del which could be used as del letters[0][0]
As #Barmar said: list.pop) can return an element by index and remove it from the list.
You can try this if you want to delete the element by index value of the list:
del letters[0][0] # [['b', 'c'], ['a', 'b', 'c']]
del letters[1][0] # [['a', 'b', 'c'], ['b', 'c']]
or if you want remove specific value in the first occurance:
letters[0].remove('a') # [['b', 'c'], ['a', 'b', 'c']]
letters[1].remove('a') # [['a', 'b', 'c'], ['b', 'c']]

adding list as a sublist in a nested list at the start of the nested list Python

given a nested list:
input_list = [['c', 'd'], ['e', 'f']]
addition_to_input_list = ['a', 'b']
required_output = [['a', 'b'], ['c', 'd'], ['e', 'f']]
for my current program, it is enough to put the addition at the start, in the future I may have to also put the addition at a specific index in the nested list.
Thanks in advance
This is a simple list insertion. It doesn't matter that the elements are lists themselves. So, this will do it:
input_list.insert( 0, addition_to_input_list )
Or you can build a new list:
required_output = [addition_to_input_list] + input_list
Proof that both options work:
>>> input_list = [['c', 'd'], ['e', 'f']]
>>> addition_to_input_list = ['a', 'b']
>>> input_list.insert(0,addition_to_input_list)
>>> input_list
[['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> input_list = [['c', 'd'], ['e', 'f']]
>>> [addition_to_input_list]+input_list
[['a', 'b'], ['c', 'd'], ['e', 'f']]
>>>

Removing repeated sub-lists from a list

I have a list as follows:
l = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
The result should be:
[['A', 'C', 'D'], ['B', 'E'], ['F']]
The order of elements is also not important.
I tried as:
print list(set(l))
Does numpy has better way
Lists are not a "hashable" type and cannot be members of a set.
Frozen sets can, so we first convert to those (also making the sublists order-insentive), and later convert back to lists.
print map(list, set(map(frozenset, l)))
or if you prefer comprehensions,
print [list(x) for x in {frozenset(x) for x in l}]
I doubt numpy offers any "better" (for some definition of better) way.
This way is IMO the clearest and most pythonic.
The reason lists cannot be part of sets is that they are mutable, so the hash now is different from the hash after they are changed; being in a hash-based set would make for confusing behavior.
#!/usr/bin/python
l1 = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
l2=[]
for l in l1:
if l not in l2:
l2.append(l)
print l2
OUTPUT
[['A', 'C', 'D'], ['B', 'E'], ['F']]
The easiest and straightforward approach where you don't need to convert a non hashable type to hashable and vice versa (which has a performance impact), is to use itertools.groupby
Off-course, the order won;t be maintained but in any case OP categorically specified that it is not a strict requirement
>>> l = [['A', 'C', 'D'], ['B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'D'], ['B', 'E'], ['F']]
>>> from itertools import groupby
>>> [k for k, g in groupby(sorted(l))]
[['A', 'C', 'D'], ['B', 'E'], ['F']]

Sorting lists based on a particular element - Python

How do I sort a list of lists based on the first element of the lists in Python?
>>> list01 = (['a','b','c'],['b','a','d'],['d','e','c'],['a','f','d'])
>>> map(sorted, list01)
[['a', 'b', 'c'], ['a', 'b', 'd'], ['c', 'd', 'e'], ['a', 'd', 'f']]
>>> sorted(map(sorted, list01))
[['a', 'b', 'c'], ['a', 'b', 'd'], ['a', 'd', 'f'], ['c', 'd', 'e']]
Python's sorted() can receive a function to sort by.
If you want to sort by the first element in each sublist, you can use the following:
>>> lst = [[2, 3], [1, 2]]
>>> sorted(lst, key=lambda x: x[0])
[[1, 2], [2, 3]]
For more information on sorted(), please see the official docs.
from operator import itemgetter
sorted(list01, key=itemgetter(0))
>>> sorted(list01, key=lambda l: l[0])
[['a', 'b', 'c'], ['a', 'f', 'd'], ['b', 'a', 'd'], ['d', 'e', 'c']]
Is this what you mean?
Apart from the passing a key function to the sorted (as show in earlier answers) you can also pass it a cmp (comparison) function in Python2 as follows:
sorted(list01, cmp=lambda b, a: cmp(b[0], a[0]))
Output of above expression would be same as that of using the the key function.
Although they have removed the cmp argument in Python3 from sorted, https://docs.python.org/3.3/library/functions.html#sorted, and using a key function is the only choice.

Remove all items of same name from list of sublists

I'm trying to remove all instances of a certain string from a list which contains sublists. For example, something like this:
myarray = ['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
ends up like this
mylist = [['b'],['c','d'],['d']]
after removing all the instances of 'a'.
I have used this code:
def delnodata(lst, what):
for index, item in enumerate(lst):
if type(item) == list:
delnodata(item, what)
else:
if item == what:
lst.remove(item)
delnodata(mylist, 'a')
but the output is:
[['b', 'a'], ['c', 'd'], 'a', ['a', 'd']]
I've seen a lot of similar questions on this site, but unfortunately my programming skills aren't good enough to put this together myself!
I'd do this recursively. This will also work for an arbitrary nesting level.
myarray = ['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
def nestremove(lst, what):
new = []
for item in lst:
if isinstance(item,list):
new.append(nestremove(item,what))
elif item != what:
new.append(item)
return new
print(myarray)
myarray = nestremove(myarray, 'a')
print(myarray)
The function returns a new list, so we don't have to remove items from the original list while iterating over it, which as others have already pointed out can be dangerous (see this question, especially the comments). Instead, you can just reassign myarray.
output:
['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
[['b'], ['c', 'd'], ['d']]
First use for for index, item in enumerate(lst[:]) so it loops through the entire copy of lst second delnodata(myarray, 'a') not delnodata(mylist, 'a') as you have put it
myarray = ['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
def delnodata(lst, what):
for index, item in enumerate(lst[:]):
if type(item) == list: # This if statement is optional
delnodata(item, what)
else:
if item == what:
lst.remove(item)
print lst
delnodata(myarray, 'a')
The following code returns a new list, with 'a's removed. It doesn't modify lists in place, which can cause mysterious problems.
source
myarray = ['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
def testme(data):
for item in data:
if type(item) is list:
yield list( testme(item) )
elif item != 'a':
yield item
res = list( testme(myarray) )
print res
assert res==[['b'],['c','d'],['d']], res
output
[['b'], ['c', 'd'], ['d']]
removing one item at a time from a list is very inefficient, as the following items all need to be shifted to fill the space each time. You should just create a new filtered list instead
>>> def remover(data, r):
... return [remover(x, r) if isinstance(x, list) else x for x in data if x != r]
...
>>> myarray = ['a', 'a', ['b', 'a', 'a'], ['a', 'c', 'd', 'a'], 'a', ['a', 'd']]
>>> remover(myarray, 'a')
[['b'], ['c', 'd'], ['d']]

Categories

Resources