Python list comprehension - generating multiple data - python

import random
M = 4
N = 3
def generisanjevol1(nekalista, m):
return random.choices(nekalista, k=m)
def generisanjevol2(nekalista, m,n):
#obj = [[random.choice(nekalista,k=m)] for i in range(N)]]
obj = [[random.choice(nekalista)] for i in range(n)]
return obj
#def poredjenje()
listaslova = ['A', 'B', 'C', 'D', 'E']
lista = generisanjevol1(listaslova, M)
lista2 = generisanjevol2(listaslova, M, N)
print(lista)
print(lista2)
So above is my try (generisanjevol2(nekalista, m,n)...
What I am trying to do is next:
I want to generate N of arrays and fill them with strings which are generated by random.choice function and they still must be strings from listaslova)
Perhaps let's say N=3 (N represents numbers of arrays) and M=4 (M represents length of array) I should get something like this (doesn't have to be same data in arrays, because of course they are randomly generated):
[A,C,D,E]
([A,C,E,D] [E,C,B,A] [E,D,D,A])
But the results which I get are following:
[A,D,E,C]
[[B],[D],[E]]
P.S If I try the one which is commented I get an error

The error in your commented line is because you have an extra ]. And random.choice should be random.choices.
But you also shouldn't put another list around the call to random.choice(). It already returns a list.
def generisanjevol2(nekalista, m,n):
obj = [random.choices(nekalista,k=m) for i in range(n)]
return obj

Like #Barmar said, you indeed have an extra [].
Your function should look:
def generisanjevol2(nekalista, m,n):
...: obj = [random.choices(nekalista, k=m) for i in range(n)]
...: return obj

Related

if a function can be created based on different input information?

I have the following question, I am wondering if there is a solution or not.
Because I just learned the function can be a variable in python, I am wondering if it is possible to design a function which create different function based on the input.
let's say, we have a long list of chars:
longlist = abcdefghijklmnopqrstuvwxyz
Given the an test list, test = [1,2,3]
An function (func1) can read the test list as input and return a function (func2) as output.
This function can be used to separate the long list of chars into different group and print out
a,bc,def,g,hi,jkl,o,pq.... which follow the test list 1,2,3 pattern and repeat again.
if the test list is test = [1,2,3,4]
then func1(test) --> func2
func2(longlist) prints out a,bc,def,ghij,k,lm,n
In this case, it follows the 1,2,3,4,1,2... pattern
The example I made looks not so interesting, but the fundamental question is if the function can be created based on different input information?
Yes. This is called a closure. The inner function (func2) keeps the scope that it was defined in. Try this:
def func1(x):
def func2(y):
ret = []
for f in x * len(y):
ret += [y[:f]]
y = y[f:]
if not y:
return ret
return func2
print(func1([1, 2, 3, 4])('This should do what you want'))
You can define a function within the first function and return it later. Function 1 can be used to set up params, etc. Below is an implementation of your particular question.
def make_func(params):
# Params must be a list of integers
def split_string_in_pattern(string):
res = []
pattern_index = 0
while True:
res.append(string[:params[pattern_index]])
print(res)
string = string[params[pattern_index]:]
print(string)
if not string:
return res
if pattern_index >= len(params) - 1:
pattern_index = 0
else:
pattern_index += 1
return split_string_in_pattern
""" Test """
long_string = 'asdqweasdasdacasdasdadas'
split_func = make_func([1,2,3,4])
split_func(long_string)
from itertools import permutations, combinations
# Here you can use which one is more suited for your situation: permutations or combinations
def func1(test):
def func2(longlist):
result = []
for t in test:
perms = permutations(longlist, t)
result += perms
result = [''.join(t) for t in result]
return result
return func2
f2 = func1([1, 2])
print(f2('abc'))
You get
['a', 'b', 'c', 'ab', 'ac', 'ba', 'bc', 'ca', 'cb'] if you used permutations
['a', 'b', 'c', 'ab', 'ac', 'bc'] if you used combinations

More elegant way to implement regexp-like quantifiers

I'm writing a simple string parser which allows regexp-like quantifiers. An input string might look like this:
s = "x y{1,2} z"
My parser function translates this string to a list of tuples:
list_of_tuples = [("x", 1, 1), ("y", 1, 2), ("z", 1, 1)]
Now, the tricky bit is that I need a list of all valid combinations that are specified by the quantification. The combinations all have to have the same number of elements, and the value None is used for padding. For the given example, the expected output is
[["x", "y", None, "z"], ["x", "y", "y", "z"]]
I do have a working solution, but I'm not really happy with it: it uses two nested for loops, and I find the code somewhat obscure, so there's something generally awkward and clumsy about it:
import itertools
def permute_input(lot):
outer = []
# is there something that replaces these nested loops?
for val, start, end in lot:
inner = []
# For each tuple, create a list of constant length
# Each element contains a different number of
# repetitions of the value of the tuple, padded
# by the value None if needed.
for i in range(start, end + 1):
x = [val] * i + [None] * (end - i)
inner.append(x)
outer.append(inner)
# Outer is now a list of lists.
final = []
# use itertools.product to combine the elements in the
# list of lists:
for combination in itertools.product(*outer):
# flatten the elements in the current combination,
# and append them to the final list:
final.append([x for x
in itertools.chain.from_iterable(combination)])
return final
print(permute_input([("x", 1, 1), ("y", 1, 2), ("z", 1, 1)]))
[['x', 'y', None, 'z'], ['x', 'y', 'y', 'z']]
I suspect that there's a much more elegant way of doing this, possibly hidden somewhere in the itertools module?
One alternative way to approach the problem is to use pyparsing and this example regex parser that would expand a regular expression to possible matching strings. For your x y{1,2} z sample string it would generate two possible strings expanding the quantifier:
$ python -i regex_invert.py
>>> s = "x y{1,2} z"
>>> for item in invert(s):
... print(item)
...
x y z
x yy z
The repetition itself supports both an open-ended range and a closed range and is defined as:
repetition = (
(lbrace + Word(nums).setResultsName("count") + rbrace) |
(lbrace + Word(nums).setResultsName("minCount") + "," + Word(nums).setResultsName("maxCount") + rbrace) |
oneOf(list("*+?"))
)
To get to the desired result, we should modify the way the results are yielded from the recurseList generator and return lists instead of strings:
for s in elist[0].makeGenerator()():
for s2 in recurseList(elist[1:]):
yield [s] + [s2] # instead of yield s + s2
Then, we need to only flatten the result:
$ ipython3 -i regex_invert.py
In [1]: import collections
In [2]: def flatten(l):
...: for el in l:
...: if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
...: yield from flatten(el)
...: else:
...: yield el
...:
In [3]: s = "x y{1,2} z"
In [4]: for option in invert(s):
...: print(list(flatten(option)))
...:
['x', ' ', 'y', None, ' ', 'z']
['x', ' ', 'y', 'y', ' ', 'z']
Then, if needed, you can filter the whitespace characters:
In [5]: for option in invert(s):
...: print([item for item in flatten(option) if item != ' '])
...:
['x', 'y', None, 'z']
['x', 'y', 'y', 'z']
Recursive solution (simple, good for up to few thousand tuples):
def permutations(lot):
if not lot:
yield []
else:
item, start, end = lot[0]
for prefix_length in range(start, end+1):
for perm in permutations(lot[1:]):
yield [item]*prefix_length + [None] * (end - prefix_length) + perm
It is limited by the recursion depth (~1000). If it is not enough, there is a simple optimization for start == end cases. Dependin on the expected size of list_of_tuples it might be enough
Test:
>>> list(permutations(list_of_tuples)) # list() because it's an iterator
[['x', 'y', None, 'z'], ['x', 'y', 'y', 'z']]
Without recursion (universal but less elegant):
def permutations(lot):
source = []
cnum = 1 # number of possible combinations
for item, start, end in lot: # create full list without Nones
source += [item] * (end-start+1)
cnum *= (end-start+1)
for i in range(cnum):
bitmask = [True] * len(source)
state = i
pos = 0
for _, start, end in lot:
state, m = divmod(state, end-start+1) # m - number of Nones to insert
pos += end-start+1
bitmask[pos-m:pos] = [None] * m
yield [bitmask[i] and c for i, c in enumerate(source)]
The idea behind this solution: actually, we are kind of looking full string (xyyz) though a glass wich adds certain number of None. We can count numer of possible combinations by calculating product of all (end-start+1). Then, we can just number all iterations (simple range loop) and reconstruct this mask from the iteration number. Here we reconstruct the mask by iteratively using divmod on the state number and using remainder as the number of Nones at the symbol position
The part generating the different lists based on the tuple can be written using list comprehension:
outer = []
for val, start, end in lot:
# For each tuple, create a list of constant length
# Each element contains a different number of
# repetitions of the value of the tuple, padded
# by the value None if needed.
outer.append([[val] * i + [None] * (end - i) for i in range(start, end + 1)])
(The whole thing would be again be written with list comprehension but it makes the code harder to read IMHO).
On the other hand, the list comprehension in [x for x in itertools.chain.from_iterable(combination)] could be written in a more concise way. Indeed, the whole point is to build an actual list out of an iterable. This could be done with : list(itertools.chain.from_iterable(combination)). An aternative would be to use the sum builtin. I am not sure which is better.
Finally, the final.append part could be written with a list comprehension.
# use itertools.product to combine the elements in the list of lists:
# flatten the elements in the current combination,
return [sum(combination, []) for combination in itertools.product(*outer)]
The final code is just based on the code you've written slightly re-organised:
outer = []
for val, start, end in lot:
# For each tuple, create a list of constant length
# Each element contains a different number of
# repetitions of the value of the tuple, padded
# by the value None if needed.
outer.append([[val] * i + [None] * (end - i) for i in range(start, end + 1)])
# use itertools.product to combine the elements in the list of lists:
# flatten the elements in the current combination,
return [sum(combination, []) for combination in itertools.product(*outer)]

slice a list based on some values

Hi I'm looking for a way to split a list based on some values, and assuming the list's length equals to sum of some values, e.g.:
list: l = ['a','b','c','d','e','f']
values: v = (1,1,2,2)
so len(l) = sum(v)
and I'd like to have a function to return a tuple or a list, like: (['a'], ['b'], ['c','d'], ['d','e'])
currently my code is like:
(list1,list2,list3,list4) = (
l[0:v[0]],
l[v[0]:v[0]+v[1]],
l[v[0]+v[1]:v[0]+v[1]+v[2]],
l[v[0]+v[1]+v[2]:v[0]+v[1]+v[2]+v[3]])`
I'm thinking about make this clearer, but closest one I have so far is (note the results are incorrect, not what I wanted)
s=0
[list1,list2,list3,list4] = [l[s:s+i] for i in v]
the problem is I couldn't increase s at the same time while iterating values in v, I'm hoping to get a better code to do so, any suggestion is appreciated, thanks!
If you weren't stuck on ancient Python, I'd point you to itertools.accumulate. Of course, even on ancient Python, you could use the (roughly) equivalent code provided in the docs I linked to do it. Using either the Py3 code or equivalent, you could do:
from itertools import accumulate # Or copy accumulate equivalent Python code
from itertools import chain
# Calls could be inlined in listcomp, but easier to read here
starts = accumulate(chain((0,), v)) # Extra value from starts ignored when ends exhausted
ends = accumulate(v)
list1,list2,list3,list4 = [l[s:e] for s, e in zip(starts, ends)]
Maybe make a generator of the values in l?
def make_list(l, v):
g = (x for x in l)
if len(l) == sum(v):
return [[next(g) for _ in range(val)] for val in v]
return None
You could just write a simple loop to iterate over v to generate a result:
l = ['a','b','c','d','e','f']
v = (1,1,2,2)
result = []
offset = 0
for size in v:
result.append(l[offset:offset+size])
offset += size
print result
Output:
[['a'], ['b'], ['c', 'd'], ['e', 'f']]
The idea here is using a nested loop. Assuming that your condition will always holds true, the logic then is to run through v and pick up i elements from l where i is an number from v.
index = 0 # this is the start index
for num in v:
temp = [] # this is a temp array, to hold individual elements in your result array.
for j in range(index, index+num): # this loop will pickup the next num elements from l
temp.append(l[j])
data.append(temp)
index += num
Output:
[['a'], ['b'], ['c', 'd'], ['e', 'f']]
The first answer https://stackoverflow.com/a/39715361/5759063 is the most pythonic way to do it. This is just the algorithmic backbone.
Best I could find is a two line solution:
breaks=[0]+[sum(v[:i+1]) for i in range(len(v))] #build a list of section indices
result=[l[breaks[i]:breaks[i+1]] for i in range(len(breaks)-1)] #split array according to indices
print result

divide list using recursion

I am trying to implement this function using recursion, the function takes a function parameter f where when passed a value it will return as true or false. It should check all values in the list and store all true values in a list and false values in another list returning them in a tuple.
def divL(f, l):
if not l:
return ([],[])
else:
a = list()
b = list()
for i in range(len(l)):
if f(l[i]):
a.append(l[i])
else:
b.append(l[i])
return (a, b)
Recursive version.
But I agree with others that it is better to do this without recursion.
def divL(f, l):
if not l:
return ([],[])
else:
a, b = divL(f,l[1:])
if f(l[0]):
a.insert(0, l[0])
else:
b.insert(0, l[0])
return (a, b)
#-- test ---
def f(x): return x > 0
divL(f,[1,-2,3,4,2,-5])
([1, 3, 4, 2], [-2, -5])
To solve this problem recursively, then you can start with:
def div_l(fn, elements):
if not elements:
return ([], [])
else:
trues, falses = div_l(fn, elements[1:])
if fn(elements[0]):
trues.append(elements[0])
else:
falses.append(elements[0])
return (trues, falses)
One thing to note about your code, is that, at the moment, there are no recursive calls. In the code above, our base case is when the list of elements is empty (if not elements). Then, we constantly check the first element of the list to see if it satisfies fn, appending it to trues or falses appropriately. Then we pass all the elements of the list besides the first one (elements[1:]) to the function again and repeat until the list is empty.
Having said that, the problem does not seem to be recursive in nature. Why not just use list comprehensions:
a = [element for element in l if f(element)]
b = [element for element in l if not f(element)]
Also, names like a, b, l and f are not great because they say nothing about what they actually mean.
Regarding the way you have written your code so far, the Pythonic way to iterate through the elements of a list is not the same as languages like C/C++/Java/etc; you should rarely need to get list items using their index. Instead you can re-write your for statement as follows:
for element in l:
if f(element):
a.append(element)
else:
b.append(element)
P.S. I haven't tested the code above yet, but it should be a reasonable starting point.
Recursive function that takes split lists as parameters:
def _R(f, l, ts, fs):
if not l:
return ts, fs
if f(l[0]):
return _R(f, l[1:], ts + l[:1], fs)
return _R(f, l[1:], ts, fs + l[:1])
def R(f, l):
return _R(f, l, [], [])
print R( lambda x: x > 10, range(20) )

Python 2 dimensional table and distinct entries

I'm making a function called different(). It needs to take a two-dimensional table as input and return the number of distinct entries in the table. I'm not sure how to start it,m I would really appreciate some suggestions. When used, it should look like this in the shell:
t = [[1,0,1], [0,1,0]]
different(t)
>>2
This is what I have so far:
def different()-> int
''' takes a two-dimensional table and returns number of distinct entries'''
t = []
while
#use set method?
I think there are two possible interpretations
>>> set(j for i in t for j in i)
set([0, 1])
and
>>> set(tuple(i) for i in t) # equivalent to set(map(tuple, t))
set([(0, 1, 0), (1, 0, 1)])
Either way, different should return the len of the set
def different(t):
return len(set(...))
If you like itertools, you can do the following
from itertools import chain
def different(t):
return len(set(chain.from_iterable(t)))
def different(t):
return len(set(tuple(item) for item in t))
From basic knowledge of python you can solve the above problem
t = [[1,0,1], [0,1,0], [1,2,3], [1,0,1]]
a = []
for i in t:
if i not in a:
a.append(i)
print len(a)
you have created a new list name 'a' and you have inserted all those element in the list which are unique. And afetrwards you can get the length of the new list a.

Categories