How to numerically sort string in list - python

I have a list inside of a list, and the inner list has strings of numbers (float) and words.
What I need to sort the list by, is in position list[0]. So for example,
list = [['8.34', 'a'],['3.55', 'c'],['5.92', 'b']]
I'm trying to sort the list numerically to look like
list = [['3.55', 'c'],['5.92', 'b'],['8.34', 'a']]
I've tried
sorted(list, key = float)
but I get an error message: 'float() argument must be a string or a number' and I've tried using lambda as well. Neither works. Could someone help please?

You can try passing a lambda function.:
sorted(my_list, key = lambda x : float(x[0]))
x will be an element of the list (which is also a list, because my_list is a list of lists), and float(x[0]) will return the float representation of the first element of that list.
Demo:
>>> my_list = [['8.34', 'a'],['3.55', 'c'],['5.92', 'b']]
>>> print sorted(my_list, key = lambda x : float(x[0]))
[['3.55', 'c'], ['5.92', 'b'], ['8.34', 'a']]
Note:
Don't use list as the name of a variable, because you will hide its built-in implementation.

Your list contains lists, so you cannot use float directly. You need to use a function that returns float value of the first item in each list.
>>> lis = [['8.34', 'a'],['3.55', 'c'],['5.92', 'b']]
>>> lis.sort(key=lambda x: float(x[0]))
>>> lis
[['3.55', 'c'], ['5.92', 'b'], ['8.34', 'a']]

This earlier answer can be used in your case also:
How to sort a list of lists by a specific index of the inner list?
from operator import itemgetter
list = [['8.34', 'a'],['3.55', 'c'],['5.92', 'b']]
print sorted(list, key=itemgetter(0))
gives the desired output:
[['3.55', 'c'], ['5.92', 'b'], ['8.34', 'a']]

Related

python: remove single quotation mark from elements in list. AttributeError: 'list' object has no attribute 'split'

from this list
lst=['a,b,c','d,e']
I want to obtain the following one
lst=['a','b','c','d','e']
so I assumed that first of all the quotation marks from the first list should be removed,
but this line
[i for i in lst.split(' ' ' ')]
produces this error message:
AttributeError: 'list' object has no attribute 'split'
How should I change my code to get what I need ?
I know I already answered, I just noticed that since the elements are strings and have comma separations, you could use str.join on the list then just str.split the result to get the desired output:
','.join(lst).split(',')
>>> lst = ['a,b,c','d,e']
>>> ','.join(lst).split(',')
['a', 'b', 'c', 'd', 'e']
Note this works in this case but only because of your particular values.
If you want to use a list comprehension, it'll look like this:
[y for x in lst for y in x.split(',')]
The error is because you're calling split on a list, but you need to call it on a str. The for x in lst gives you strings as x, which you then call split(',') on to get y, which is what goes into the final list.
This is equivalent to:
output = []
for x in lst:
for y in x.split(','):
output.append(y)
You should first iterate through each text in your lst list, split those texts on comma and then flatten the split text's characters into a list like this:
lst=['a,b,c','d,e']
character_lst = [char for text in lst for char in lst.split(",")
# character_list will contain ['a','b','c','d','e']
Using itertools.chain:
from itertools import chain
list(chain(*(s.split(',') for s in lst)))
or as a (slower) full functional variant:
from itertools import chain
list(chain(*map(lambda x: x.split(','), lst)))
output:
['a', 'b', 'c', 'd', 'e']
Without imports or nested loops:
lst = ['a,b,c','d,e']
output = []
for x in lst:
output.extend(x.split(','))

Replace elements in a list of lists python

I have a list of lists as follows:
list=[]
*some code to append elements to list*
list=[['a','bob'],['a','bob'],['a','john']]
I want to go through this list and change all instances of 'bob to 'b' and leave others unchanged.
for x in list:
for a in x:
if "bob" in a:
a.replace("bob", 'b')
After printing out x it is still the same as list, but not as follows:
list=[['a','b'],['a','b'],['a','john']]
Why is the change not being reflected in list?
Because str.replace doesn't work in-place, it returns a copy. As immutable objects, you need to assign the strings to elements in your list of lists.
You can assign directly to your list of lists if you extract indexing integers via enumerate:
L = [['a','bob'],['a','bob'],['a','john']]
for i, x in enumerate(L):
for j, a in enumerate(x):
if 'bob' in a:
L[i][j] = a.replace('bob', 'b')
Result:
[['a', 'b'], ['a', 'b'], ['a', 'john']]
More Pythonic would be to use a list comprehension to create a new list. For example, if only the second of two values contains names which need checking:
L = [[i, j if j != 'bob' else 'b'] for i, j in L]
You can try using a dictionary object of python
import numpy as np
L = [['a','bob'],['a','bob'],['a','john']]
dic = {'bob':'b'} # you can specify more changes here
new_list = [dic.get(n, n) for n in np.concatenate(L)]
print(np.reshape(new_list,[-1,2]).tolist())
Result is
[['a', 'b'], ['a', 'b'], ['a', 'john']]
I'm going to use a simple example, but basically x is another variable and isn't linked to the list element. You have to change the list element directly in order to alter the list.
l=[1,2,3,4]
for x in l:
x=x+1
This doesn't change the list
l=[1,2,3,4]
for i,x in enumerate(l):
l[i]=x+1
this changes the list
I might be a little to the party, but a more Pythonic way of doing this is using a map and a list comprehension. It can operate on a list of the list with any number of values.
l = [['a','bob'],['a','bob'],['a','john']]
[list(map(lambda x: x if x != 'bob' else 'b', i)) for i in l]
it gives you the desired output
[['a', 'b'], ['a', 'b'], ['a', 'john']]
The main idea is that the inner loop is iterating through the inner loop and using the simple lambda function to perform the replacement.
I hope that this helps anyone else who is looking out for something similar.
This is the case because you are only changing the temporary variable a.
list = [1,2,3]
for i in list:
i+=1
list will still be [1,2,3]
you have to edit the string based on its index in the list

If statement that keeps characters only

Let's say we have a list list_a = [a,b,C,.,/,!,d,E,f,]
i want to append to a new list only the letters of the alphabet.
So the new list will be list_b = [a,b,C,d,E,f].
So far i have tried doing it like that way:
list_b = []
for elements in list_a:
try:
if elements == str(elements):
list_b.append(elements)
except ValueError: #Catches the Error when the element is not a letter
continue
However, when i print the list_b it has all the elements of list_a , it doesn't do the job i expected.
Any ideas ?
PS: comma in the specific example brings Error too.
You can use the .isalpha() method of the string type.
In [1]: list_a = ['a','b','C','.','/','!','d','E','f']
In [2]: list_b = [i for i in list_a if i.isalpha()]
In [3]: list_b
Out[3]: ['a', 'b', 'C', 'd', 'E', 'f']
Try checking if the character is an alphabet by using the .isalpha() function.
list_b = []
for elements in list_a:
if elements.isalpha():
list_b.append(elements)
You are missing the fact that the str() function does not return the "str" elements you think it does, just an str representation of them.
Try creating a list with you dictionary [a-zA-Z] (not very pythonic but simple to grasp) and check if your character exists in it.
I suggest writing your own code from scratch instead of copy/pasting, that is the only way to really understand the problem....
You can try this:
import string
for item in list_a:
if item in string.ascii_letters:
list_b.append(item)
Also, check out the string module. It has a lot of additional methods that can help you, should you wish to work with strings. Do note that this works only with ascii characters. If you want to check for every character in an alphabet, then you can via the isalpha() method, as the others have noted above.
Well, it is basically the same logic of using isalpha() method, but you can do this by using filter:
list_a = ['a','b','C','.','/','!','d','E','f']
list_b = list(filter(lambda i: i.isalpha(), list_a))
print(list_b)
Output:
['a', 'b', 'C', 'd', 'E', 'f']
You can use the string or re package to do this
import re
new_list = [c for c in old_list if re.match(r'[a-zA-Z]', c)]
Or with string
import string
new_list = [c for c in old_list if c in string.ascii_letters]

Remove list element without mutation

Assume you have a list
>>> m = ['a','b','c']
I'd like to make a new list n that has everything except for a given item in m (for example the item 'a'). However, when I use
>>> m.remove('a')
>>> m
m = ['b', 'c']
the original list is mutated (the value 'a' is removed from the original list). Is there a way to get a new list sans-'a' without mutating the original? So I mean that m should still be [ 'a', 'b', 'c' ], and I will get a new list, which has to be [ 'b', 'c' ].
I assume you mean that you want to create a new list without a given element, instead of changing the original list. One way is to use a list comprehension:
m = ['a', 'b', 'c']
n = [x for x in m if x != 'a']
n is now a copy of m, but without the 'a' element.
Another way would of course be to copy the list first
m = ['a', 'b', 'c']
n = m[:]
n.remove('a')
If removing a value by index, it is even simpler
n = m[:index] + m[index+1:]
There is a simple way to do that using built-in function :filter .
Here is ax example:
a = [1, 2, 3, 4]
b = filter(lambda x: x != 3, a)
If the order is unimportant, you can use set (besides, the removal seems to be fast in sets):
list(set(m) - set(['a']))
This will remove duplicate elements from your original list though
We can do it via built-in copy() function for list;
However, should assign a new name for the copy;
m = ['a','b','c']
m_copy=m.copy()
m_copy.remove('a')
print (m)
['a', 'b', 'c']
print(m_copy)
['b', 'c']
You can create a new list without the offending element with a list-comprehension. This will preserve the value of the original list.
l = ['a', 'b', 'c']
[s for s in l if s != 'a']
Another approach to list comprehension is numpy:
>>> import numpy
>>> a = [1, 2, 3, 4]
>>> list(numpy.remove(a, a.index(3)))
[1, 2, 4]
We can do it without using in built remove function and also without creating new list variable
Code:
# List m
m = ['a', 'b', 'c']
# Updated list m, without creating new list variable
m = [x for x in m if x != a]
print(m)
output
>>> ['b', 'c']
The question is useful as I sometimes have a list that I use throughout my given script but I need to at a certain step to apply a logic on a subset of the list elements. In that case I found it useful to use the same list but only exclude the needed element for that individual step, without the need to create a totally new list with a different name. For this you can use either:
list comprehension: say you have l=['a','b','c'] to exclude b, you can have [x for x in l if x!='b']
set [only if order is unimortant]: list(set(l) - set(['b'])), pay attention here that you pass 'b' as list ['b']

Splitting a list

I've scoured various resources and can't figure out how to do a rather simple operation.
Right now, I have a list as follows:
li = [['a=b'],['c=d']]
I want to transform this into:
li = [['a','b'],['c','d']]
As I understand it, split("=") only applies to string types. Is there an equivalent method for lists?
Pardon the simplicity of my question...
-Dan
You want this:
[x[0].split('=') for x in li]
# prints [['a', 'b'], ['c', 'd']]
To grab a question from a comment further down the post, the reason split works for x[0] is that x represents the inner list. That's accomplished by the for x in li. Also, I fixed mine to read for x in li and not for x in test as I had assigned your examples to a variable called 'test' on my system.
You can use map():
>>> li = [['a=b'],['c=d']]
>>> map(lambda x: x[0].split('='), li)
[['a', 'b'], ['c', 'd']]
This traverses the list li and applies the lambda function to every element. As every element of the list is again a list with one element, x[0] takes this element, which is a string, splits it and returns a new list with both values.
Warning - its been a while since I did any python, but your issue is more general.
You are correct in that split applies to strings.
What you need to do is split the VALUE contained in your list not the list itself.
So you would do something like
newValue = split('=', li[0][0])
li[0] = newValue
Is this what you are looking for ?
map(lambda y:y.split('='),map(lambda x:x[0], li))
You can do it with this:
[k[0].split("=") for k in li]
Presuming each sublist consists of individual strings of the form a=b:
>>> [el[i].split('=') for el in li for i in range(len(el))]
[['a', 'b'], ['c', 'd']]
(Indeed, what you're splitting is the inner string a=b. So the split() string method works fine.)
EDIT: A much more elegant way of doing this double list comprehension is:
>>> [a.split('=') for el in li for a in el]
[['a', 'b'], ['c', 'd']]
There have been a number of good suggestions made, so the OP should be able to learn a good amount of Python for it. Important to remember is that what is being split is li[i][j], ie an item of the list that is an item of the list li.

Categories