How to flatten Nested Sequence in Python - python-2.7

I have a nested sequence that I want to flatten into a single list of values.

Please try this general solution:
Write a recursive generator function involving a yield from
statement. For example:
from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x, ignore_types)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
print(x)

I'd go with recursion but split in a balanced way.
def flatten(lst):
n = len(lst)
if n == 0:
return lst
elif n == 1:
item = lst[0]
try:
return flatten(list(item))
except TypeError:
return [item]
else:
k = n // 2
return flatten(lst[:k]) + flatten(lst[k:])
Demo
items = [1, 2, [3, 4, [5, 6], 7], 8]
flatten(items)
[1, 2, 3, 4, 5, 6, 7, 8]

Related

How to print out lists in a list

Note: code created in python 2.7
I am taking a robotics class in school and we are learning python.
The task was to take
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
and print it out as such
1
2
3
4
5
6
7
8
9
When I tried my code out I got the error message
I tried looking at what this means online but I am just starting to learn python and I didn't understand any of the answers that I found.
What am I doing wrong? How do I fix my code?
First Post sorry about the mess
Reason why you get an error:
You get the error in the line
results.append(lists[numbers[each_list]])
because numbers is an integer and numbers[each_list] isn't a valid function. So instead use the square brackets correctly:
results.append(lists[numbers][each_list])
Other Methods:
You don't really need to use range function:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
for i in n:
for j in i:
print(j)
or a one liner:
print('\n'.join(str(j) for i in n for j in i))
Or if you are flattening a nested list:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
def flat(lis):
res = []
for i in lis:
for j in i:
res.append(j)
return res
flat_n = flat(n)
or a one-liner:
>>> n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
>>> flat = lambda x: [j for i in x for j in i]
>>> flat(n)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
or just simply:
flat_n = [j for i in n for j in i]
n=[[1,2,3],[4,5,6,7,8,9]]
def flatten(lists):
results=[]
for lists in n:
for numbers in lists:
results.append(numbers)
return results
new_list =(flatten(n))
for num in new_list:
print (num)
When Executed
1
2
3
4
5
6
7
8
9
>>>

Python list append different lists in the same scope for the same variable

Okay. I write an algorithm for show me all the permutations of a list of integers. But during the algorithm I got a problem to append a permuted list to my result list.
The code is the heap's algorithm. I got my finished permutation when size == 1. So a can append the permutated list V to my final list res. Here's the code:
The function for permutate the list
def permutations(V, size):
global res
if size == 1:
print(V)
res.append(V)
for i in range(0, size):
permutations(V, size-1)
if size % 2 == 1:
V[size-1], V[0] = V[0], V[size-1]
else:
V[i], V[size-1] = V[size-1], V[i]
A = [1,2,3]
res = []
permutation(A, len(A))
print(res)
And this is the output:
[1, 2, 3]
[2, 1, 3]
[3, 1, 2]
[1, 3, 2]
[2, 3, 1]
[3, 2, 1]
res: [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
The printed permutations of V are all correct. But the list V append to my global res are not change. They are being append right after the print and the list append is different.
If you change the lines like this:
res.append(V)
|
|
v
D = [V[i] for i in range(len(V))]
res.append(D)
The results is correct on the final. Anyone can explain how can a printed list can be different from a appended list using the same variable.
Replace res.append(V) with res.append(list(V)) simply fixes your issue.
All V you appended to the res are references to the same object. This can be observed by printing the id of each element in the list:
for i in res:
print(id(i))

Classification of same rows in 2D numpy

Hi i want to classify indexes of same rows in 2D numpy array. Is there any function to do it ?
Something like this :
a= [[1,2,3] , [2,3,4] , [5,6,7] ,[1,2,3] ,[1,2,3] , [2,3,4]]
then f(a) returns same row indexes [[0,3,4],[1,5],[2]]
I would appreciate for your solutions
Here's one to output list of arrays of row indices -
def classify_rows(a):
sidx = np.lexsort(a.T)
b = a[sidx]
m = ~(b[1:] == b[:-1]).all(1)
return np.split(sidx, np.flatnonzero(m)+1)
If you need a list of lists as output -
def classify_rows_list(a):
sidx = np.lexsort(a.T)
b = a[sidx]
m = np.concatenate(( [True], ~(b[1:] == b[:-1]).all(1), [True]))
l = sidx.tolist()
idx = np.flatnonzero(m)
return [l[i:j] for i,j in zip(idx[:-1],idx[1:])]
Sample run -
In [78]: a
Out[78]:
array([[1, 2, 3],
[2, 3, 4],
[5, 6, 7],
[1, 2, 3],
[1, 2, 3],
[2, 3, 4]])
In [79]: classify_rows(a)
Out[79]: [array([0, 3, 4]), array([1, 5]), array([2])]
In [80]: classify_rows_list(a)
Out[80]: [[0, 3, 4], [1, 5], [2]]

Generating random lists in Python query

I want my program to take numbers from 1 to X and randomly distribute those numbers between X/2 numbers of lists Y times. I don't want a number to be repeated during one shuffle, also I don't want the lists to repeat at all. So if there is list [1,2] there shouldn't be another list containing 1 or 2 in same shuffle and there shouldn't be another [1,2] or [2,1] in the whole result.
This is what I came up with, however, it keeps on repeating numbers. Any adice?
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
numberslist = range(1,amount+1)
twos = []
thisshuffle = []
final = []
while len(final) < (amount/2)*times:
twos = []
thisshuffle = []
while len(twos) < 2:
if len(numberslist)!=0:
randomnumber = random.choice(numberslist)
if (randomnumber in twos) or (randomnumber in thisshuffle):
numberslist.remove(randomnumber)
else:
twos.append(randomnumber)
thisshuffle.append(randomnumber)
numberslist.remove(randomnumber)
else:
numberslist = range(1,amount+1)
if (twos or list(reversed(twos))) not in final:
final.append(twos)
k=0
for i in range(times): #this shit prints shit
print "%s:" % (i+1), final[k:k+amount/2]
print
k = k + amount/2
Shuffler()
Shuffler()
As ccf pointed out, your requirements aren't trivial. A few more steps and you'd have a sudoku generator :)
I tried a few solutions but they either didn't produce random output or were rather inefficient. Ccf's solution is clearly well written but it seems to have the same problem; it produces ordered output (e.g. [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]).
#cff - wouldn't it be better to use itertools.combinations rather than itertools.permutations to avoid generating repetitions?
Here's a "solution" that's quite similar to ccf's (doesn't produce random output either):
import itertools
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
perms = list(itertools.combinations(rng, 2))
lst_single = []
lst_all = []
for p in perms:
if len(lst_all) >= times:
for i, lst in enumerate(lst_all):
print str(i+1) + ": ", lst
break
if len(lst_single) == amount/2:
lst_all.append(lst_single)
lst_single = []
elif p[0] < p[1]:
p = list(p)
lst_single.append(p)
Shuffler()
Output
Numbers up to: 6
Number of shuffles: 3
1: [[1, 2], [1, 3], [1, 4]]
2: [[1, 6], [2, 3], [2, 4]]
3: [[2, 6], [3, 4], [3, 5]]
And here's a slightly hackish solution that seems to produce the output you want but in an inefficient way. It relies on a set for filtering out unwanted combinations but still wastes resources producing them in the first place.
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
final = []
lst_len = amount/2
combos_unique = set()
while len(combos_unique) < lst_len*times:
combo_rand = random.sample(rng, 2)
if combo_rand[0] < combo_rand[1]:
combos_unique.add(tuple(combo_rand))
tmp = []
for combo in combos_unique:
tmp.append(list(combo))
if len(tmp) >= lst_len:
final.append(tmp)
tmp = []
for i, lst in enumerate(final):
print str(i+1) + ": ", lst
Shuffler()
Output
Numbers up to: 6
Number of shuffles: 3
1: [[2, 6], [4, 6], [5, 6]]
2: [[4, 5], [1, 3], [1, 6]]
3: [[3, 4], [2, 4], [3, 5]]
You don't want any repeated numbers in one shuffle, and any repeated list ... and so on. This is not an easy task. Plus another fact is that, the unique sets of numbers are fixed, which cannot be set too high. For example, if you set "Numbers up to:" 5, and "Number of shuffles: " 20, for sure you will get repeated numbers.
The issue with your code, I see, is in this if statement:
if (twos or list(reversed(twos))) not in final:
final.append(twos)
(twos or list(reversed(twos))) is logical OR, the result is twos, because twos is not empty. I suggest you change the if statement to:
if (twos not in final) and (list(reversed(twos)) not in final):
final.append(twos)
The following code (python 2.7x) uses permutations and shuffle to generate numbers list. Next, make the list unique (e.g., no [1,2] and [2,1] in same list). then, divide them into groups based on number of shuffles specified by the user. Press any letter, script will exit. Hope it helps:
from itertools import permutations
from random import shuffle
def Shuffler():
try:
amount = input("Numbers up to: ")
p = list(permutations(range(1, amount + 1), 2))
p_uniq = [list(x) for x in p if x[::-1] in p and x[0]<=x[1]]
shuf_max = len(p_uniq) /(amount / 2)
times = shuf_max + 1 # set a higher value to trigger prompt
while times > shuf_max:
shuffle(p_uniq) # shuffle the unique list in place
times = input("Number of shuffles (MAX %s): " % (shuf_max))
else:
for i, group in enumerate(list(zip(*[iter(p_uniq[: (amount /2) * times + 1])]* (amount/2)))):
print "%i: " % (i + 1), list(group)
Shuffler()
except:
print 'quitting...'
Shuffler()
Output:
Numbers up to: 10
Number of shuffles (MAX 9): 8
1: [[6, 7], [1, 9], [2, 5], [5, 9], [9, 10]]
2: [[1, 10], [3, 8], [4, 10], [8, 10], [1, 5]]
3: [[1, 4], [6, 8], [3, 6], [2, 4], [4, 7]]
4: [[2, 10], [5, 8], [3, 9], [1, 7], [4, 9]]
5: [[1, 2], [7, 9], [1, 3], [6, 9], [1, 6]]
6: [[2, 9], [4, 8], [3, 5], [8, 9], [7, 10]]
7: [[2, 7], [2, 3], [7, 8], [3, 7], [3, 10]]
8: [[3, 4], [2, 6], [5, 6], [5, 7], [4, 6]]
Numbers up to:

How to copy list items certain amount of times?

I have a big list of around 2000 numbers in the list. This is just an example of what I want.
I have list1=[1,2,3,4] and list2=[1,3,2,5]. I want it so that list1[i] will be used list2[i] times in the new list.
So for this example the new list would be:list3=[1,2,2,2,3,3,4,4,4,4,4]
The new list3 has 1x1, 3x2, 2x3, 5x4.
This isn't pretty and isn't particularly easy to understand, but works:
>>> list1 = [1, 2, 3, 4]
>>> list2 = [1, 3, 2, 5]
>>> import itertools
>>> list3 = list(itertools.chain(*[[list1[i]] * count for i, count in enumerate(list2)]))
>>> list3
[1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4]
Brief explanation...
You can multiply a list:
>>> [1] * 3
[1, 1, 1]
Using this in the list comprehension will get you a list-of-lists:
>>> [[list1[i]] * count for i, count in enumerate(list2)]
[[1], [2, 2, 2], [3, 3], [4, 4, 4, 4, 4]]
You can then use itertools to flatten the list as above.
list1=[1,2,3,4]
list2=[1,3,2,5]
list3 = []
for a, b in zip(list1, list2):
for i in range(b):
list3.append(a)
list3 == [1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4]
Another alternative:
list1=[1,2,3,4]
list2=[1,3,2,5]
z=[]
for x,y in zip(list1,list2):
z.extend([x] * y)
print z