I am almost finished with a task someone gave me that at first involved easy use of the product() function from itertools.
However, the person asked that it should also do something a bit different like:
li =
[[1, 2, 3],
[4, 5, 6]]
A regular product() would give something like: [1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4] ...
What it should do is:
Do a regular product(), then, add the next item from the first element in the list and so on. A complete set of example would be:
[[1, 4, 2]
[1, 4, 3],
[1, 5, 2],
[1, 5, 3],
[2, 4, 3],
[2, 5, 3],
[2, 6, 3]]
How should I use itertools in this circumstance?
EDIT:
It might help if I explain the goal of the program:
The user will enter, for example, a 5 row by 6 column list of numbers.
A normal product() will result in a 5-number combination. The person wants a 6-number combination. Where will this "6th" number come from? It would come from his choice of which row he wants.
I wondering what is the magical computations you performing, but it look's like that's your formula:
k = int(raw_input('From What row items should be appeared again at the end?'))
res = [l for l in product(*(li+[li[k]])) if l[k]<l[len(li)] ]
Generalized for more than two sublist (map function would be the other alternative)
from pprint import pprint
for li in ([[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
):
triples= []
prevlist=li[0]
for nextlist in li[1:]:
for spacing in range(1,len(prevlist)):
triples.extend([[first,other,second]
for first,second in zip(prevlist,prevlist[spacing:])
for other in nextlist])
pprint(sorted(triples))
Related
I have a question on how to map correctly my list.
I have the following code:
class Bar():
def __init__(self, i, j):
self.i = i-1
self.j = j-1
For the following list:
bars = [Bar(1,2), Bar(2,3), Bar(3,4), Bar(4,5), Bar(5,1),Bar(1,4), Bar(2,4), Bar(4,6), Bar(6,5)]
But for my problem, I have an array like this:
elementsmat=[[1, 1, 2], [2, 2, 3], [3, 3, 4], [4, 4, 5], [5, 5, 1], [6, 1, 4], [7, 2, 4], [8, 4, 6], [9, 6, 5]]
I used the following code to obtain an array where I removed the first element of each list of the list and then transformed it into a list.
s= np.delete(elementsmat, 0, 1)
r = s.tolist()
Output: [[1, 2], [2, 3], [3, 4], [4, 5], [5, 1], [1, 4], [2, 4], [4, 6], [6, 5]]
So, how can I apply the Bar function to all the elements of my new array correctly? I did this but I got the following error.
bars = map(Bar,r)
__init__() missing 1 required positional argument: 'j'
I thought it could be because in the first one the list has () and in my list I have [], but I am not sure.
You can use itertools.starmap instead of map (after importing itertools). Your current way calls Bar([1, 2]). starmap unpacks the lists into arguments. A generator/list comprehension is also an option.
(Bar(*x) for x in r)
Now you see why it's called starmap.
You need to unpack the nested lists into the call to Bar():
l = list(map(lambda x: Bar(*x), r))
itertools.starmap does the same thing.
Or, you can use a list-comprehension:
l = [Bar(i, j) for i, j in r]
A built-in functional approach
lst = [[1, 2], [2, 3], [3, 4], [4, 5], [5, 1], [1, 4], [2, 4], [4, 6], [6, 5]]
map(Bar, *zip(*lst))
I'm trying to solve this problem here: https://codingbat.com/prob/p252079?parent=/home/peter#norvig.com
In math, a "combination" of a set of things is a subset of the things. We define the function combinations(things, k) to be a list of all the subsets of exactly k elements of things. Conceptually, that's all there is, but there are some questions to settle: (A) how do we represent a subset? (B) What order are the elements within each subset? (C) What order to we list the subsets? Here's what we will agree to: (A) a subset will be a list. (B) The order of elements within a list will be the same as the order within 'things'. So, for example, for combinations([1, 2, 3], 2) one of the subsets will be [1, 2]; whereas [2, 1] is not a subset. (C) The order of subsets will be lexicographical or sorted order -- that is, combinations([1, 2, 3], 2) returns [ [1, 2], [1, 3], 2, 3] ] because [1, 2] < [1, 3] < [2, 3]. You might want to use the function 'sorted' to make sure the results you return are properly ordered.
combinations([1, 2, 3, 4, 5], 2) → [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
combinations([1, 2, 3], 2) → [[1, 2], [1, 3], [2, 3]]
combinations([1, 2, 3, 4, 5, 6], 5) → [[1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 5, 6], [1, 2, 4, 5, 6], [1, 3, 4, 5, 6], [2, 3, 4, 5, 6]]
Here's my code:
def combinations(things, k):
if k == 0 or k == len(things):
return [things]
elif len(things) < k:
return
else:
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for i in range(len(combinations(things[1:], k - 1))):
firstelement = [things[0]]
firstelement += combinations(things[1:], k - 1)[i]
finalcomb.append(firstelement)
for j in range(len(combinations(things[1:], k))):
finalcomb.append(combinations(things[1:], k)[j])
return finalcomb
However, this is the output:
Haven't hit 10 reputation yet so it's a link to the error. I'm not sure what I did wrong, can anybody help me out? Thank you so much.
The problem is this. When k == 0 it shouldn't return [things]. It should return an empty array. Similar to when len(things) < k:. This is because, when k == 0, it means we that we have already found all the numbers for that specific combination.
But there's one more problem. We're returning an empty array. However, in the for loops, we're iterating over the returned array. So if the array is empty, nothing happens. So what we should really return is an empty 2D array. I won't go into too much detail about what the problem is since it's better for you to try and understand why it's not working. Try adding print statements inside and outside the for loops.
Anyway, the working code looks like this:
def combinations(things, k):
if k == len(things):
return [things[:]]
if len(things) < k or k == 0:
return [[]]
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for comb in subcomb1:
firstelement = [things[0]]
firstelement += comb
finalcomb.append(firstelement)
finalcomb += subcomb2
return finalcomb
Note a few things:
Use the variables you've already assigned (I'm assuming you forgot about them)
Lists can be concatenated using +, similar to strings. If you return within an if statement, you don't need an else for the next line since if the if statement is satisfied, it would definitely not go to the else.
You simply can try using itertools:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 2):
output.append(list(nums))
print(output)
output:
[[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
For 3 nums:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 3):
output.append(list(nums))
print(output)
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]]
The problem is as follows: Write a function choose_gen(S, k) that produces a generator that yields all the k-element subsets of a set S (represented as a sorted list of values without duplicates) in some arbitrary order.
Here is what I have so far:
def choose_gen(l: object, k: object) -> object:
if k>len(l):
return None
elif k == len(l):
yield sorted(l)
return
for i in l:
aux = l[:]
aux.remove(i)
result = choose_gen(aux, k)
if result:
yield from result
It runs but does not avoid the duplicate subsets. Could somebody please help to solve this issue? Thanks in advance.
an example of an input would be:
print([s for s in choose_gen([1,3,5,7], 2)])
actual output: [[5, 7], [3, 7], [3, 5], [5, 7], [1, 7], [1, 5], [3, 7], [1, 7], [1, 3], [3, 5], [1, 5], [1, 3]]
expected output: [[5, 7], [3, 7], [3, 5], [1, 7], [1, 5], [1, 3]]
I am not sure. But
I think that in the 6th line you have to write something after return. You have left it empty.
Or try,
new_menu = [s for s in choose_gen([1,3,5,7], (2)]
final_new_menu = list(dict.fromkeys(new_menu))
print(final_new_menu)
I have the following code to remove from the data list all sublists for which nums is a subset.and I dont understand why its not working:
data=[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
nums=[1,2]
for each in data:
if set(nums).issubset(each):
data.remove(each)
print(data)
>>[[1, 2, 4], [1, 3, 4], [2, 3, 4]]
Why isn't [1,2,4] being removed when nums is a subset of it, as seen below?
set(nums).issubset([1,2,4])
>>True
You're modifing the list you're iterating from.
This is a nicer solution:
data=[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
nums=[1,2]
data = [each for each in data if not set(nums).issubset(each)]
print(data)
For learning purposes, see this code which also works. The difference with your code is that here we're not modifying data list in the for loop.
data=[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
nums=[1,2]
new_data = []
for each in data:
if not set(nums).issubset(each):
new_data.append(each)
data = new_data
print(data)
Because the iterator is unaware that you removed an element. When it passes to the second element, it finds [1, 3, 4] meaning that you skipped [1, 2, 4].
For your information, there is also a filterfalse function in the very useful itertools module.
from itertools import filterfalse
data = list(filterfalse(set(nums).issubset, data))
I learned to create and manage nested lists by building a NxM matrix and filling it with random integers.
I've solved it via a simple one-liner and struggled to write a comprehensive solution.
I call the first solution as a cheating because I got this tip from this website, but didn't completely understand how it works. So, I've tried to write a more detailed piece of code on my own, which was difficult, and I'm not completely sure I got it right.
The original solution:
from random import randint
size_n = int(input("Number of lists N "))
size_m = int(input("Number of elements M "))
matrix = [[randint(1,9) for m in range(size_m)] for n in range(size_n)]
print(matrix)
I had a hard time to create a list of list with the correct levels of loops in loops. I end up with the temporary matrix, but I'm not sure it's good solution.
The final solution:
from random import randint
size_n = int(input("Number of lists N "))
size_m = int(input("Number of elements M "))
matrix = []
for n in range(size_n):
tmp = []
for m in range(size_m):
tmp.append(randint(1,9))
matrix.append(tmp)
print(matrix)
Can you help me to understand what is the correct solution for the task?
P.S. Is it normal for developer to look for another solution if the code just works but you think it might be prettier?
matrix = [[randint(1,9) for m in range(size_m)] for n in range(size_n)]
Let's say our size_n is 5, for an example. Then range(size_n) gives
[0, 1, 2, 3, 4]
E. g. a list of 5 consecutive integers starting with 0. If you do something for each element of the list, that creates another list of the same size, for example:
>>>[88 for n in range(size_n)]
[88, 88, 88, 88, 88]
You are, of course, not limited by simple numbers, you can create, basically, anything. For example, empty lists:
>>>[[] for n in range(size_n)]
[[], [], [], [], []]
Then, of course, the inner lists don't have to be empty, you can populate them with numbers:
>>>[[1, 2, 3] for n in range(size_n)]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Or you can use another range expression inside:
>>> [[range(1, 4)] for n in range(5)]
[[[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]]]
And you can use list comprehension on those inner lists just the same way:
>>> [[randint(1, 9) for m in range(1, 4)] for n in range(5)]
[[8, 4, 3], [6, 7, 2], [6, 8, 2], [9, 6, 1], [9, 1, 2]]
You can go deeper and deeper until you're bored or out of memory:
>>> [[[randint(1, 9) for n in range(1, 5)] for n in range(1, 4)] for n in range(5)]
[[[2, 9, 6, 1], [6, 7, 4, 5], [5, 9, 1, 7]], [[5, 2, 9, 3], [1, 8, 9, 7], [8, 4, 4, 8]], [[4, 4, 7, 9], [7, 1, 4, 2], [7, 8, 7, 3]], [[4, 4, 9, 9], [8, 8, 9, 5], [6, 1, 3, 9]], [[5, 9, 3, 2], [7, 5, 4, 7], [7, 7, 4, 3]]]
Nested list comprehension is usually the right solution, they are easy to read once you get used to the notation. Nested loops are OK too.
There's nothing wrong with looking for better ways to re-write your working code (I'd say, rather, it's wrong not to look), unless you develop an unhealthy obsession with it.
For Python 3 range(5) actually doesn't give [0, 1, 2, 3, 4] directly, but for this task it's effectively the same thing.