"".join(list) if list contains a nested list in python? - python

I know that "".join(list) converts the list to a string, but what if that list contains a nested list? When I try it returns a TypeError due to unexpected list type. I'm guessing it's possible with error handling, but so far my attempts have been fruitless.

You could try something like this:
''.join(''.join(inner) for inner in outer)
That should work, and won't have too much trouble if the outer list contains both Strings and Lists inside of it, ''.join(myString) -> myString.

Well, if the list is nested, simply flatten it beforehand:
>>> import itertools
>>> lst = [['a', 'b'], ['c', 'd']]
>>> ''.join(itertools.chain(*lst))
'abcd'

Also you could try this snippet:
from collections import Iterable
ellipsis = type('',(),{'__str__' : lambda self:'...'})()
def flatten(collection,stack = None):
if not stack: stack = set()
if id(collection) in stack:
yield ellipsis
return
for item in collection:
if isinstance(item,Iterable):
stack.add(id(collection))
for subitem in flatten(item,stack):
yield subitem
stack.remove(id(collection))
else: yield item
x = [1,2,[3,4,[5],[[6]],7]]
x.append(x)
>>> print(', '.join(map(str,flatten(x))))
1, 2, 3, 4, 5, 6, 7, ...

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(','))

List comprehension and syntax mistakes with 3 arguments

Here is the question:
Implement function processList2(inputList, specialItem, ignoreItems) that returns a new list that contains all the items of inputList (and in the original order) except
Remove any that appear in the list ignoreItems
Occurrences of specialItem (if specialItem is not in ignoreItems) should become the string "special" in the new list.
I am trying to create a new list from inputList using list comprehension. I can get items not in ignoreItems, but can't seem to figure out how to print 'special' if item == specialItem.
Here's what I have so far:
def processList2(inputList, specialItem, ignoreItems):
return [item for item in inputList if item not in ignoreItems]
a sample output is something like:
>>> processList2([1,1,2,2], 1, [2])
['special', 'special']
or
>>> processList2([1,2,3,4,True,'dog'], 4, [3,5,4])
[1, 2, True, 'dog']
You can use the ternary operator in Python.
def processList2(inputList, specialItem, ignoreItems):
return [item if item != specialItem else "special" for item in inputList if item not in ignoreItems]
See also this post for more on the subject.

Converting string values to float and removing strings from list

I have a list that looks like this
lst = ['a','b','43.23','c','9','22']
I would like to remove the elements that cannot be represented as floats and hence I am doing the following (Attempt 1):
for i,j in enumerate(lst):
try:
lst[i]=float(j)
except:
lst.remove(j)
Which leaves the list looking like this
lst = ['b', 43.23, '9', 22.0]
whereas what I need is this
lst = [43.23, 9.0 , 22.0]
And so I'm doing the following:
for i,j in enumerate(lst):
try:
lst[i]=float(j)
except:
pass
lst = [i for i in lst if type(i) != str]
Is there a cleaner way to do this.?
EDIT: Changed the name of example list from 'list' to 'lst' based on the recommendations below.
You can use the following function from this stackoverflow post:
def isfloat(value):
try:
float(value)
return True
except ValueError:
return False
And, then use it in a list comprehension:
>>> l = ['a','b','43.23','c','9','22']
>>> [float(x) for x in l if isfloat(x)]
# [43.23, 9.0, 22.0]
First you shouldn't name your variable list it will shadow the built-in list function/class. You can use a simple function to do this:
>>> lst = ['a','b','43.23','c','9','22']
>>> def is_float(el):
... try:
... return float(el)
... except ValueError:
... pass
...
>>> [i for i in lst if is_float(i)]
['43.23', '9', '22']
>>> [float(i) for i in lst if is_float(i)] # to return a list of floating point number
[43.23, 9.0, 22.0]
The problem with your code is that you are trying to modify your list while iterating. Instead you can make a copy of your list then use the element index to remove their value.
lst = ['a','b','43.23','c','9','22']
lst_copy = lst.copy()
for el in lst:
try:
float(val)
except ValueError:
lst_copy.remove(el)
Of course this is less efficient than the solution using the list comprehension with a predicate because you first need to make a copy of your original list.
You shouldn't manipulate the list you're iterating through (and you shouldn't call it list neither, since you would shadow the built-in list), since that messes up with the indexes.
The reason why 'b' shows up in your output is that during the first iteration, 'a' is not a float, so it gets removed. Thus your list becomes:
['b','43.23','c','9','22']
and b becomes list[0]. However, the next iteration calls list[1] skipping thus 'b'.
To avoid such an issue, you can define a second list and append the suitable values to that:
l1 = ['a','b','43.23','c','9','22']
l2 = []
for item in l1:
try:
l2.append(float(item))
except ValueError: # bare exception statements are bad practice too!
pass
Would be better in considering iterators to efficiently use system memory. Here is my take to the solution.
def func(x):
try:
return float(x)
except ValueError:
pass
filter(lambda x: x, map(func, li))
Borrowing idea from this post : python: restarting a loop, the first attempt can be fixed with a simple while loop
lst = ['a','b','43.23','c','9','22']
temp = 0
while temp<len(lst):
try:
lst[temp] = float(lst[temp])
temp+=1
except ValueError:
lst.remove(lst[temp])
temp = 0
which leaves me with the desired result (by resetting the loop iterator)
lst = [43.23, 9.0 , 22.0]

convert to tuple list nested in a list of list

I need to use set(myList) but it's not possible because I have a list of lists. (It gives a not hashable error).
So I decided to convert each element in the list to a tuple. The list is more or less like this:
MyList[elem1, elem2, [nested1, nested2, [veryNested1, veryNested2]]]
How can I quickly convert everything to a tuple and then back to a list?
Use recursion
MyList = ['elem1', 'elem2', ['nested1', 'nested2', ['veryNested1', 'veryNested2']]]
print MyList
def tupconv(lst):
tuplst = []
for x in lst:
if isinstance(x, list):
tuplst.append(tupconv(x))
else:
tuplst.append(x)
return tuple(tuplst)
def listconv(tup):
lst = []
for x in tup:
if isinstance(x, tuple):
lst.append(listconv(x))
else:
lst.append(x)
return lst
mytup = tupconv(MyList)
print mytup
mylist = listconv(mytup)
print mylist
This should do it:
def lol_to_tuple(lol):
return tuple(el if type(el) is not list
else lol_to_tuple(el)
for el in lol)
To go back, just replace tuple with list:
def tuples_to_lol(tuples):
return list(el if type(el) is not tuple
else tuples_to_lol(el)
for el in tuples)
Hmm, I've seen this kind of problem before. I solved it by using recursion (on the assumption that the final element is the next level, and that I knew how deep the recursion needed to go to split it up.
Having said that, I think it might be better to ask if you were given the list in that format or if you made it like that through some process? That might help us avoid some unnecessary head-bashing.
You can flatten your list with:
In [1]: from compiler.ast import flatten
In [2]: flatten([1, 2, [11, 12, [21, 22]]])
Out[2]: [1, 2, 11, 12, 21, 22]
And then use set(myList)

How to find the number of instances of an item in a list of lists

I want part of a script I am writing to do something like this.
x=0
y=0
list=[["cat","dog","mouse",1],["cat","dog","mouse",2],["cat","dog","mouse",3]]
row=list[y]
item=row[x]
print list.count(item)
The problem is that this will print 0 because it isn't searching the individual lists.How can I make it return the total number of instances instead?
Search per sublist, adding up results per contained list with sum():
sum(sub.count(item) for sub in lst)
Demo:
>>> lst = [["cat","dog","mouse",1],["cat","dog","mouse",2],["cat","dog","mouse",3]]
>>> item = 'cat'
>>> sum(sub.count(item) for sub in lst)
3
sum() is a builtin function for adding up its arguments.
The x.count(item) for x in list) is a "generator expression" (similar to a list comprehension) - a handy way to create and manage list objects in python.
item_count = sum(x.count(item) for x in list)
That should do it
Using collections.Counter and itertools.chain.from_iterable:
>>> from collections import Counter
>>> from itertools import chain
>>> lst = [["cat","dog","mouse",1],["cat","dog","mouse",2],["cat","dog","mouse",3]]
>>> count = Counter(item for item in chain.from_iterable(lst) if not isinstance(item, int))
>>> count
Counter({'mouse': 3, 'dog': 3, 'cat': 3})
>>> count['cat']
3
I filtered out the ints because I didn't see why you had them in the first place.

Categories