I am trying to write a function that get a list of lists with different length as input and return the zipped result.
What I am looking for is that to expand my code below to any amount of lists. (I cannot use Zip Longest function since I am trying to do this on our system that does not have most of python functions including
zip longest function)
Here is my code:
a = [[1,2,3,4],[5,6],[7,8,9]]
def myzip(a):
temp1=[]
temp2=[]
temp3=[]
lens=[]
t=1
for i in a:
if(t==1):
temp1=i
lens.append(len(temp1))
t+=1
elif(t==2):
temp2=i
lens.append(len(temp2))
t+=1
elif(t==3):
temp3=i
lens.append(len(temp3))
for i in range(max(lens)):
if(i<len(temp1)):
print(temp1[i])
if(i<len(temp2)):
print(temp2[i])
if(i<len(temp3)):
print(temp3[i])
myzip(a)
Output:
1
5
7
2
6
8
3
9
4
This function works only for 3 lists because I am using Temp lists in order to achieve the zipped result But I want to make this code works for any number of lists. for example I able to run for [[1,2,3,4],[5,6],[7,8,9],[11,33]] or [[1,2,3,4],[5,6]] or [[1,2,3,4],[5,6],[7,8,9],...,[25,22]]
How about this:
from itertools import zip_longest
lists = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [11, 33]]
for item in [x for t in zip_longest(*lists) for x in t]:
if item is not None:
print(item)
Output:
1
5
7
11
2
6
8
33
3
9
4
Or to just get them as a list:
items = [x for t in zip_longest(*lists) for x in t if x is not None]
Note: #MarkM made a worthwhile remark - if your source data contains None, this approach will have a problem in that it will filter them out. You should tell zip_longest to use a different fillvalue in that case, that does not show up in your data. For example:
items = [x for t in zip_longest(*lists, fillvalue='') for x in t if x is not None]
If you cannot import itertools for very specific reasons (as mentioned in the comments), you could just use the implementation shown in the documentation (https://docs.python.org/3/library/itertools.html#itertools.zip_longest):
def repeat(object, times=None):
if times is None:
while True:
yield object
else:
for i in range(times):
yield object
def zip_longest(*args, fillvalue=None):
iterators = [iter(it) for it in args]
num_active = len(iterators)
if not num_active:
return
while True:
values = []
for i, it in enumerate(iterators):
try:
value = next(it)
except StopIteration:
num_active -= 1
if not num_active:
return
iterators[i] = repeat(fillvalue)
value = fillvalue
values.append(value)
yield tuple(values)
Something like this could also work for you:
def flatten_list(my_list):
flat_list = []
for element in my_list:
if type(element) is list: #if element is a list, iterate through it
for item in element:
flat_list.append(item)
else:
flat_list.append(element)
return flat_list
nested_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10],[1,2,3],[1,2,4],[4,6,7,8]]
print('Original List', nested_list)
print('Flat List', flatten_list(nested_list))
Output
Original List [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10], [1, 2, 3], [1, 2, 4], [4, 6, 7, 8]]
Flat List [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 1, 2, 4, 4, 6, 7, 8]
Related
As a beginner python learner I bumped up to a wall at this point and couldn't figure it out.
What I am trying to do is to be able to pick integers in multiple lists and remove the duplicates among them. Then make a copy list which does not include the duplicates.
def my_function(x):
return list(dict.fromkeys(x))
liss = [[1,2],[3,4,5,6],[1,4,3,99]]
list2 = my_function(str(liss))
list1 = [x for i in list2 for x in i]
print(list1)
Consider using a set comprehension:
>>> xss = [[1, 2], [3, 4, 5, 6], [1, 4, 3, 99]]
>>> xs_no_dups = list({x for xs in xss for x in xs})
>>> xs_no_dups
[1, 2, 3, 4, 5, 6, 99]
Please write code to implement an algorithm named "merge-sort"
You can click on these links to read the wikipedia page on merge-sort
Write code to accomplish the following tasks:
Sort each list. For example [4, 2, 1, 2, 5, 0] becomes [0, 1, 2, 3, 4, 5]
merge the sorted lists. For example, merge [1, 3, 4, 9] and [2, 6, 20] to form [1, 2, 3, 4, 6, 20]
traverse the final sorted merged list from left to right. If the current element is different from the previous element, then output the current element.
Consider the following list, named the_list:
OUTPUTS (VALUES) [1, 1, 1, 5, 5, 6, 9, 9, 9, 9, 14, 14, 14]
INPUTS (INDICIES) 0 1 2 3 4 5 6 7 8 9 10 11 12
Go through the list from left-to-right.
Notice that the_list[0] is 1.
1 has not been seen before.
So, you should send 1 to the output stream.
We are finished processing the_list[0]
Next, take a look at the_list[1].
the_list[1] is equal to the previous value.
So, do NOT send the_list[1] to the output stream.
Only when the input changes do we send the input to the output stream.
As long as the input is the same as what it was 2 seconds ago, we send no output to the output stream.
def foobar(the_list):
# `prev` stands for the English word `previous`
the_list = iter(the_list)
prev = next(the_list)
yield prev
for elem in the_list:
if elem != prev:
yield elem
prev = elem
I have a list of lists. I want to collect all of the sublists with the same first element, combine their elements, and remove duplicates. I'm getting close, but my current solution dies on an index error.
Current output:
[[1, 2, 3, 7, 8, 9], [5, 5, 8], [2, 2, 0, 2, 3, 4, 5, 6]]
Correct output:
[[1, 2, 3, 7, 8, 9], [4, 5, 6, 3, 2], [5, 5, 8], [2, 2, 0]] (not necessarily in that order)
Code:
listoflist = [[1,2,3,1],[4,5,6],[1,7,8],[4,3,2],[5,5,8],[2,2,0],[1,9,9]]
try: #(try and except is to deal with when lists are removed)
for i in range(len(listoflist)): #iterating forwards
x = listoflist[i][0] #indexing through sublists and setting the first value
for j in range(len(listoflist)-1,0,-1): #iterating backwards
if x == listoflist[j][0] and listoflist[i] != listoflist[j]: #comparing
listoflist[i].extend(listoflist[j]) #combining lists and removing the old list
listoflist.remove(listoflist[j])
new = set(listoflist[i]) #conversion to set and back to list
listoflist[i] = list()
for obj in new:
listoflist[i].append(obj)
print listoflist[i]
print listoflist
except IndexError:
print listoflist
ANALYSIS
Your main problem is that you violate a basic practice: do not change an iterable while you're iterating on it. Your outer loop runs i through values 0-5. However, by the time you get to 4, you no longer have an item #4 in the list. I did some simple tracing on your code, including a better message on error:
except IndexError:
print "ERROR", i, j, listoflist
Output:
ERROR 4 1 [[1, 2, 3, 1, 1, 9, 9, 1, 7, 8], [4, 5, 6, 4, 3, 2], [5, 5, 8], [2, 2, 0]]
REPAIR
Don't alter the original list. Instead, build a new list from the old one. Gather all of the lists that begin with the same element; append the resulting set to the result you want.
listoflist = [[1,2,3,1],[4,5,6],[1,7,8],[4,3,2],[5,5,8],[2,2,0],[1,9,9]]
result = []
try:
for i in range(len(listoflist)):
x = listoflist[i][0]
if x < 0: # Skip any sub-list already used
continue
gather = listoflist[i][:] # Copy list for processing
for j in range(len(listoflist)-1,0,-1):
if x == listoflist[j][0] and i != j:
gather.extend(listoflist[j])
listoflist[j][0] = -j # Uniquely mark this as not in use.
print i, j, gather
result.append(list(set(gather)))
print i, result
print result
except IndexError:
print "ERROR", i, j, listoflist
Yes, this is still much longer than needed; if you really want to dig into Python, you can group the lists by first element and do all the processing in one long line. I've tried to keep this more accessible for you.
Here is my solution. I went for building dict{} based on the first elem in the list as the key, and merging the lists based on that.
listoflist = [[1,2,3,1],[4,5,6],[1,7,8],[4,3,2],[5,5,8],[2,2,0],[1,9,9]]
temp_dict = {}
result_list = []
# build a dict{int:list[]} based on first elem of list
for ll in listoflist:
if ll[0] not in temp_dict:
temp_dict[ll[0]]=ll
else:
for x in ll:
temp_dict[ll[0]].append(x)
# now build a list of list with our dict
for key, values in temp_dict.items():
temp_list = []
temp_list.append(key)
for x in values:
if x not in temp_list:
temp_list.append(x)
result_list.append(temp_list)
print(result_list)
Output:
[[1, 2, 3, 7, 8, 9], [4, 5, 6, 3, 2], [5, 8], [2, 0]]
I have a list that is:
[2,3,5,"TAG",6,7,3,2,6,"TAG",9,9,8,3]
I want to return a list containing nested sublists of values that are in between the "TAG"s.
So the resulting list would look like:
[[2,3,5], [6,7,3,2,6], [9,9,8,3]]
I created a method below that attempts to accomplish this but does not work:
def returnListBetweenTag(lst, tag):
temp = []
k = lst.index(tag)
while lst != []:
temp.append(lst[0:k])
del lst[0:k+1]
return temp
This prints out:
[[2, 3, 5], [6, 7, 3], [6, 'TAG', 9], [8, 3]]
Can anyone please help me understand what I am doing wrong, and some suggestions to fix it?
This is reasonably straight forward when using a generator like:
Code:
def divide_list(a_list, divider):
sub_list = []
for item in a_list:
if item == divider:
yield sub_list
sub_list = []
else:
sub_list.append(item)
yield sub_list
Test Code:
data = [2,3,5,"TAG",6,7,3,2,6,"TAG",9,9,8,3]
print(list(divide_list(data, "TAG")))
Results:
[[2, 3, 5], [6, 7, 3, 2, 6], [9, 9, 8, 3]]
Here's a way to accomplish this with itertools.groupby.
from itertools import groupby
ls = []
for key, group in groupby(lst, lambda x: x != "TAG"):
if key:
ls.append(list(group))
print ls
# [[2, 3, 5], [6, 7, 3, 2, 6], [9, 9, 8, 3]]
This can also be implemented as a comprehension:
ls = [list(group) for key, group in groupby(lst, lambda x: x != "TAG") if key]
This is really not a good way to do it, but you can make it work.
First, you never do the k = lst.index(tag) again after the first time.
So, with your list, k turns out to be 3 forever. But you keep taking the first three elements off the list, so first k[0:3] is [2, 3, 5], then it's [6, 7, 3], then it's 3, [6, 'TAG', 9], and so on. You need to keep calling it each time.
Second, what happens when there are no more 'TAG's left in the list? That lst.index will raise an exception. So you need to handle that.
def returnListBetweenTag(lst, tag):
temp = []
while lst != []:
try:
k = lst.index(tag)
except ValueError:
temp.append(lst)
break
temp.append(lst[0:k])
del lst[0:k+1]
return temp
Logic is just tracking the 'TAG' keyword and when it found just empty the temp list and start adding from index 0 again.
This will work for you:
data=[2,3,5,"TAG",6,7,3,2,6,"TAG",9,9,8,3]
def values(datae):
final_values=[]
store=[]
for i in data:
if i!='TAG':
store.append(i)
else:
final_values.append(store)
store=[]
final_values.append(store)
return final_values
print(values(data))
output:
[[2, 3, 5], [6, 7, 3, 2, 6], [9, 9, 8, 3]]
So im attempting to create a recursion function where it takes each item in the list and sums it up altogether, now I know theres a simple built in function sum(a) but I'm trying to work with nested lists such as this below but I keep getting thrown an error.
def sumList():
list2 = [1, [2, 3,[4, 5, 6], 7, [8, [9, 10]], 11]]
newlist = []
lol = 0
for i in range (len(list2)):
if type(list2[i]) == type([]):
print list2[i], "here"
for i in range (len(list2[i])):
lol += (len(list2[i]))
newlist.append(i[:len(i)+1])
if len(list2)==0:
return None
else:
print list2[i]
lol+=list2[i]
print lol
sumList()
Now I know i've got a lot implemented in the program that I imagine isn't needed, but the error I
keep getting is
1
[2, 3, [4, 5, 6], 7, [8, [9, 10]], 11] here
TypeError: object of type 'int' has no len()
In general, you could flatten your list of lists and search for min in the flattened list. There are many recipes for flattening. Below is one that I took from here.
import collections
def flatten(iterable):
for el in iterable:
if isinstance(el, collections.Iterable) and not isinstance(el, str):
yield from flatten(el)
else:
yield el
list2 = [2, 3, [4, 5, 6], 7, [8, [9, 10]], 11]
print(list(flatten(list2)))
# [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(sum(flatten(list2)))
# 65
def r_sum(mylist,nsum=0):
for i in mylist:
if isinstance(i,int):
nsum += i
else:
nsum += r_sum(i)
return nsum
# Python 2.7
def recursiveSum(data):
# This naively assumes that if it's not an int, it's a list
# You may want to add more error handling if you expect dirtier data
if isinstance(data, int): return data
mySum = 0
for i in data: mySum += recursiveSum(i)
return mySum
list2 = [1, [2, 3,[4, 5, 6], 7, [8, [9, 10]], 11]]
print recursiveSum(list2) # Should get 66
I have a list[] of items from which I'd like to display one randomly, but the displayed item must not repeat more than once in last x requests.
list1 = item1, item2, item3, item4,
item5, item6, item7, item8, item9,
item 10
Display a random selection
from the list above
list2 = store the last displayed item in list2 which should only store 7
items, not more
Display a random
selection from the list but make
sure it doesn't exist in the
list2
Is that the right way to do it? Either way, I'd like to know how to limit a list to store only 7 items?
Thanks
collections.deque is the only sequence type in python that naturally supports being bounded (and only in Python 2.6 and up.) If using python 2.6 or newer:
# Setup
from collections import deque
from random import choice
used = deque(maxlen=7)
# Now your sampling bit
item = random.choice([x for x in list1 if x not in used])
used.append(item)
If using python 2.5 or less, you can't use the maxlen argument, and will need to do one more operation to chop off the front of the deque:
while len(used) > 7:
used.popleft()
This isn't exactly the most efficient method, but it works. If you need speed, and your objects are hashable (most immutable types), consider using a dictionary instead as your "used" list.
Also, if you only need to do this once, the random.shuffle method works too.
Is this what you want?
list1 = range(10)
import random
random.shuffle(list1)
list2 = list1[:7]
for item in list2:
print item
print list1[7]
In other words, look at random.shuffle(). If you want to keep the original list intact, you can copy it: list_copy = list1[:].
You could try using a generator function and call .next() whenever you need a new item.
import random
def randomizer(l, x):
penalty_box = []
random.shuffle(l)
while True:
element = l.pop(0)
# for show
print penalty_box, l
yield element
penalty_box.append(element)
if len(penalty_box) > x:
# penalty time over for the first element in the box
# reinsert randomly into the list
element = penalty_box.pop(0)
i = random.randint(0, len(l))
l.insert(i, element)
Usage example:
>>> r = randomizer([1,2, 3, 4, 5, 6, 7, 8], 3)
>>> r.next()
[] [1, 5, 2, 6, 4, 8, 7]
3
>>> r.next()
[3] [5, 2, 6, 4, 8, 7]
1
>>> r.next()
[3, 1] [2, 6, 4, 8, 7]
5
>>> r.next()
[3, 1, 5] [6, 4, 8, 7]
2
>>> r.next()
[1, 5, 2] [4, 3, 8, 7]
6
>>> r.next()
[5, 2, 6] [4, 3, 8, 7]
1
>>> r.next()
[2, 6, 1] [5, 3, 8, 7]
4
>>> r.next()
[6, 1, 4] [3, 8, 2, 7]
5
Something like:
# Setup
import random
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = []
# Loop for as long as you want to display items
while loopCondition:
index = random.randint(0, len(list1)-1)
item = list1.pop(index)
print item
list2.append(item)
if(len(list2) > 7):
list1.append(list2.pop(0))
I'd use set objects to get a list of items in list1 but not in list2:
import random
list1 = set(["item1", "item2", "item3", "item4", "item5",
"item6", "item7", "item8", "item9", "item10"])
list2 = []
while True: # Or something
selection = random.choice(tuple(list1.difference(set(list2))))
print(selection)
list2.append(selection)
if len(list2) > 7:
list2 = list2[-7:]