Create a list from a tuple of tuples - python

I am looking for a different way to get a string list from a tuple of tuples. This is how I do right now:
x = (('a',1), (2,3), (4,), (), (None,))
op_list = []
for item in x:
if item and item[0]:
op_list.append(str(item[0]))
print op_list
Output: ['a', '2', '4']
I cannot think of any other way to get to the list. My question is, is there any better/alternate/pretty way of doing this?
EDIT: Added a few pitfall inputs to the input, like an empty tuple, tuple with None and given the expected output as well. Also edited the question to ensure that I need only a list of strings irrespective of any other data type other than None.

>>> x = (('a',1), (2,3), (4,))
>>> [str(item[0]) for item in x if item and item[0]]
['a', '2', '4']

Maybe using map and lambda functions gives you the easiest and more compact way to do it:
>>> x = (('a',1), (2,3), (4,), (None,), ())
>>> filter(None, map(lambda i: str(i[0]) if len(i) > 0 and i[0] != None else None, x))
['a', '2', '4']

Use itemgetter.
from operator import itemgetter
f = itemgetter(0)
def func(i):
if not i:
return None
r = f(i)
if r:
return str(r)
Using it:
>>> x = (('a',1), (2,3), (4,), None, '', False, [], (None,), ())
>>> filter(None, map(func, x))
['a', '2', '4']
You can make it into a function:
def extract_first_non_none(collection):
return filter(None, map(func, collection))
Or into a class:
class Extractor():
def __init__(self, index):
self.getter = itemgetter(index)
def _func(self, item):
if not item:
return None
r = self.getter(item)
if r != None:
return str(r)
def extract(self, collection):
return filter(None, map(self._func, collection))
Using the class:
>>> x = (('a',1), (2,3), (4,), None, '', False, [], (None,), ())
>>> e = Extractor(0)
>>> e.extract(x)
['a', '2', '4']

Related

Combile two multidimensional list into one list

I have two lists that I wanted to merge:
list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
I wanted to arrange them into this list:
new_list = [('desktop', ['10022', '9964']), ('mobile', ['119', '117']), ('tablet', ['7', '8'])]
then, I also wanted to compute the percentage difference between the integers and insert the answer in the list:
updated_list = [['desktop', '10022', '9964', '0.5821'], ['mobile', '119', '117', '1.7094'], ['tablet', '7', '8', '-12.5']]
Here's my rough code:
from collections import OrderedDict
list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
merged = OrderedDict()
for list_ in list1, list2:
for k, v in list_:
try:
merged[k].append(v)
except:
merged[k] = [v]
def diff(x, y):
return ((x/y)-1)*100
updated_list = [[row,x,y,diff(x,y) for x,y in vals.items()] for row,vals in merged.items()]
Can't get this thing to work :(
Assuming that your lists is sorted and homogeneous, you can
[[k, int(v1), int(v2), int(v1)/int(v2) - 1] for ((k, v1), (_, v2)) in zip(list1, list2)]
If lists data is homogeneous, but not sorted, simply call
list1.sort()
list2.sort()
prior to processing it. If data is not homogeneous, simple way to iterate over is to cast lists to dictionaries and iterate over common keys:
d1, d2 = dict(list1), dict(list2)
[[k, int(d1[k]), int(d2[k]), int(d1[k])/int(d2[k]) -1] for k in d1.keys() & d2.keys()]
Here is a working code:
# The same, and then
updated_list = [(row, vals[0], vals[1], diff(int(vals[0]), int(vals[1]))) for row, vals in merged.items()]
print(updated_list)
Your problem was that you wanted to unpack x and y from vals, but you can't do that unless vals is a list of tuples.
In
updated_list = [[row,x,y,diff(x,y) for x,y in vals.items()] for row,vals in merged.items()]
vals is a list, so it has no method items(), the inner list-comprehension has a syntax error and would not work even if it were [(row,x,y,diff(x,y) )for x,y in vals.items()] or some such, because of the wrong method call. Also you wouldn't unpack a list of 2 with for x,y in vals. You'd unpack a list of 2-tuples like that, for example.
This'll deviate from what you've tried, but you could create an ordered default dict, merge, and do your calculations:
In [1]: from collections import OrderedDict
In [2]: class OrderedDefaultDict(OrderedDict):
...: def __missing__(self, key):
...: obj = self[key] = self.default_factory()
...: return obj
...: def __init__(self, default_factory, *args, **kwgs):
...: super().__init__(*args, **kwgs)
...: self.default_factory = default_factory
...:
In [11]: list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
In [12]: list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
In [14]: merged = OrderedDefaultDict(list)
In [16]: from itertools import chain
In [17]: for k, v in chain(list1, list2):
...: merged[k].append(v)
...:
In [18]: merged
Out[18]: OrderedDefaultDict([('desktop', ['10022', '9964']), ('mobile', ['119', '117']), ('tablet', ['7', '8'])])
In [19]: def diff(x, y):
....: return ((x/y)-1)*100
....:
In [20]: [[k, x, y, str(diff(float(x), float(y)))]
...: for k, (x, y) in merged.items()]
Out[20]:
[['desktop', '10022', '9964', '0.5820955439582498'],
['mobile', '119', '117', '1.7094017094017033'],
['tablet', '7', '8', '-12.5']]
Or format the floats as you see fit, for example
'{:.4f}'.format(diff(...))

Map if it can be converted

I have the following list:
a = ['1', '2', 'hello']
And I want to obtain
a = [1, 2, 'hello']
I mean, convert all integers I can.
This is my function:
def listToInt(l):
casted = []
for e in l:
try:
casted.append(int(e))
except:
casted.append(e)
return casted
But, can I use the map() function or something similar?
Sure you can do this with map
def func(i):
try:
i = int(i)
except:
pass
return i
a = ['1', '2', 'hello']
print(list(map(func, a)))
a = ['1', '2', 'hello']
y = [int(x) if x.isdigit() else x for x in a]
>> [1, 2, 'hello']
>> #tested in Python 3.5
Maybe something like this?

Int convert to str using for cycle

why such construction doesn't work?
l = [1,2,3]
for x in l:
x = str(x)
print(l)
it returnes:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
instead of expected:
['1', '2', '3']
['1', '2', '3']
['1', '2', '3']
For each iteration you're printing the original list without modifying it.
Use map()
list(map(str, l))
>> ['1', '2', '3']
or a list comprehension
l = [str(x) for x in l]
When you do x = str(x) it changes the value in x to str (and not the element in your list l)
But as you are trying to change the list l
I suggest you try a list comprehension:
l = [str(x) for x in l]
You need to store back the casted x back to the list as below:
l = [1,2,3]
new_l = []
for x in l:
new_l.append(str(x))
print(new_l)
Also,if you're not accustomed with map (see other answers) you could use :
for i,x in enumerate(l):
l[i] = str(x)
But other answers are just better.

Remove duplicate from two lists without using loop?

I have two list:
a=['1','2','3','3','3']
b=['a','b','c','d','e']
these two lists have the same amount of items. I want to delete duplicate in a and for b with same index. for this example, I would like to have the result as
a=['1','2','3']
b=['a','b','c']
I am not so familiar with Python, the only way I think is to use loop
for item in a
if find duplicate
delete b with same index
I want to ask, is there any better way to do this, other than using loop?
You can use a set for this:
>>> seen = set()
>>> new_a, new_b = [], []
>>> for x, y in zip(a, b):
... if x not in seen:
... new_a.append(x)
... new_b.append(y)
... seen.add(x)
...
>>> new_a
['1', '2', '3']
>>> new_b
['a', 'b', 'c']
Another way to do it using itertools.compress(Python 2.7+ and 3.1+ only):
>>> from itertools import compress, tee
>>> seen = set()
>>> f1, f2 = tee(True if x not in seen and not seen.add(x) else False for x in a)
>>> list(compress(a, f1))
['1', '2', '3']
>>> list(compress(b, f2))
['a', 'b', 'c']
You can use set for removing duplicate entries in a list. Please use following code to get desired output.
#!/usr/bin/python
a=['1','2','3','3','3']
b=['a','b','c','d','e']
a=set(a)
print list(a)
lena=len(a)
b=set(b)
b=list(b)
print b[:lena]
output:
>>>
['1', '3', '2']
['a', 'c', 'b']

Is there a str.join() for lists?

I understand str.join():
>>> '|'.join(['1','2','3'])
'1|2|3'
Is there something which outputs a list? Is there a function that will output:
['1', '|', '2','|', '3']
That is, a str.join() for lists? (or any other iterable?)
list('|'.join(['1','2','3']))
should do the trick where you are working with a list of chars.
A more generic solution, that works for all objects is:
from itertools import izip_longest, chain
def intersperse(myiter, value):
return list(
chain.from_iterable(izip_longest(myiter, [], fillvalue=value))
)[:-1]
I'm not aware of a built-in/std-library version of this function.
In action:
print intersperse([1,2,3], '|')
outputs:
[1, '|', 2, '|', 3]
How about this?
>>> list('|'.join(['1','2','3']))
['1', '|', '2', '|', '3']
a = [1, 2, 'str', 'foo']
print [x for y in a for x in y, '|'][:-1]
# [1, '|', 2, '|', 'str', '|', 'foo']
For the general case, consider the roundrobin itertools recipe
This simple generator avoids building a list (faster, saves memory):
def intersperse(iterable, element):
iterable = iter(iterable)
yield next(iterable)
while True:
next_from_iterable = next(iterable)
yield element
yield next_from_iterable
Example:
>>> list(intersperse(['1', '2', '3'], '|'))
['1', '|', '2', '|', '3']

Categories

Resources