import itertools
Num = 11
base = list(range(1,Num+1))
Permutations = list(itertools.permutations(base))
I'm getting a memory error trying to run this. In reality I only need to generate the 1st (Num-1)! permutations but I'm not sure how to (so if Num = 7 i would need to generate the first 6! = 720 permutations). But I would ideally like to be able to generate permutations for significantly higher values of Num so any suggestions would be great
range() and permutation() both return generators that generate items on demand. You don't need to call list() and turn them into lists. Just iterate over them directly and access the items one by one.
num = 11
base = range(1, num+1)
permutations = itertools.permutations(base)
for permutation in permutations:
# Do something with `permutation`.
(Note that a generator can only be used once. If you want to iterate over the permutations more than once you'll need to call itertools.permutations() multiple times.)
To stop after n items use itertools.islice():
for permutation in itertools.islice(permutations, n):
# Do something with `permutation`.
You can skip items at the beginning, too. This would skip the first five permutations:
for permutation in itertools.islice(permutations, 5, n):
# Do something with `permutation`.
If you want to count the permutations you can add enumerate(), which attaches an index to every entry:
for i, permutation in enumerate(itertools.islice(permutations, n)):
# Skip the fifth permutation.
if i == 4:
continue
# Do something with `permutation`.
By the way, please use lowercase for variable names. Only class names should be capitalized.
Related
I have a function called "first_funtion()" that returns a list of 100 instances of a class.
Then I want to define a second function that is going to create a new list with random instances taken from the output list of first_function(), something like:
first_funtion()
def second_function(list2, N):
list2 = list2(random.choice(first_function()))
The thing is that I want list2 to be always greater than N, so if N = 5 I want the random list2 to be more than 5 instances. If N = 10 then I want the list to be more that 10 instances.
How can I do that?
You can first create the list using first_function, then draw a random integer in the range between N and the length of the list and then draw a random sample from the list.
import random
def second_function(list2, N):
len_list = len(list2)
length = random.randint(N, len_list)
return random.sample(list2, length)
You can do it by using two random function;
Use first one to choose a value of N from the range excluding N to including lenght of list1, i.e, (N, len(list1)]
x = random.randint(N+1, len(list1)
And use second one to choose x number of values from list_1;
random.choices(list1, k=x)
So, the code will look something like this:
import random
def second_function(list1, N):
x = random.randint(N+1, len(list1))
y = random.choices(list1, k=x)
print(y)
Here randint(start, stop) includes both start and stop numbers while generating random integer. It will generate a random number from the inclusive range.
Andrandom.choices () function returns total k number of random items from any list.
Note: You may get repeated values if you're using random.choices (). So, use random.sample() function when you want to choose multiple random items from a list without repetition or duplicates.
You can visit on this link and explore more related to this.
As the random.choice() function always picks one element from the list, so you can iterate through the list more than N number of times and use random.choice() each time. And you can also use random.randint() to get a random number above N, to be used in the range function for the for loop.
import random
def second_function(list2, N):
for i in range(N,random.randint(N,len( first function() ))) :
list2.append(random.choice(first_function()))
return list2
I'm defining a function (results) that contains a for loop whose result is a random number (a). So, if the loop runs 10 times, for example, it will generate 10 different numbers. I would like to store those numbers in a list within the loop that I could then print to see what numbers were generated.
I thought of using append, though I don't know how to do this. This is my code so far, though the print statement doesn't work (I get an error saying I didn't use append correctly).
import maths
def results():
items = []
for _ in range(1,10):
a = maths.numbers()
items.append(a)
print(items)
You could do something like this:
import maths
list_with_numbers=[]
def results():
for _ in range(1,10):
a = maths.numbers()
list_with_numbers.append(a)
print(list_with_numbers)
It is obvious, but don´t forget to all the function itself.
.append needs to be called on the list, not on a. list also needs to be initialized outside of the loop in order to be able to append to it. Here's a fixed version of your method:
from random import random
def results():
# First, initialize the list so that we have a place to store the random values
items = []
for _ in range(1,10):
# Generate the next value
a = random()
# Add the new item to the end of the list
items.append(a)
# Return the list
return items
Here is some more documentation on the append() method that further explains how it works.
It's also worth noting that range generates values from the start value up to (but not including) the stop parameter. So if your intent was to generate 10 values, you should do range(0, 10) since range(1, 10) will only give you 9 values.
If you wanted to take this a step further, you could use a list comprehension to avoid needing to use append altogether, and provide a parameter to indicate how many random numbers you want:
def results(num=10):
return [random() for _ in range(0, num)]
# produces a list of 10 random numbers (by default)
foo = results()
# produces a list of 20 random numbers
bar = results(20)
append is a method you have to use on the list, so basically you would do like this: randomList.append(a) and don't forget to initialize your liste beforehand at the beginning of your function: randomList = []
You have a few minor mistakes
there is no maths module
a is the number, not the list. You should append on a list
you call print after the loop ends, not on every iteration
from random import random
def results():
numbers = []
for _ in range(1,10):
a = random()
print(a)
numbers.append(a)
return numbers
import random as rd
ListNumbers1 = []
List1 = []
for j in range(1000):
ListNumbers1 = rd.randint(1,10000)
How would i get the 50 highest numbers from ListNumbers1 and append to list1?
Something like this?
List1.extend(sorted(ListNumbers1)[-50:])
You're assigning the same value over and over in your loop, destroying your list in the process. Use append...
Better: create a list comprehension of the numbers, then use heapq.nlargest to directly get the 50 highest numbers:
import random as rd
import heapq
highest_50 = heapq.nlargest(50,[rd.randint(1,10000) for _ in range(1000)])
print(highest_50)
a result:
[9994, 9983, 9983, 9968, 9934, 9925, 9913, 9912, 9909, 9909, 9902, 9889, 9884, 9880, 9811, 9794, 9793, 9792, 9765, 9756, 9750, 9748, 9738, 9737, 9709, 9707, 9704, 9700, 9691, 9686, 9635, 9618, 9617, 9605, 9604, 9593, 9586, 9584, 9573, 9569, 9569, 9557, 9531, 9528, 9522, 9438, 9438, 9431, 9402, 9400]
Just for fun, I have a more efficient solution:
from random import randint
import heapq
# create a list of 1000 random numbers
# take the negative, so the min heap does what we want
dataset = [-randint(1, 10000) for _ in range(1000)]
# O(n) function to impose the heap invariant
heapq.heapify(dataset)
# sorting is O(n log n)
# extracting from a heap is log n per item
# therefore taking the 50 biggest is much more efficent if
# we use a heap to extract only the ones we need
top50 = [-heapq.heappop(dataset) for _ in range(50)]
print top50
This is a faster solution because the 50 you want to extract is much less than the 1000 total input size. I renamed the variables, but that's just my personal preference.
Like that (notice how assigning random number is fixed):
import random as rd
ListNumbers1 = []
List1 = []
for j in range(1000):
ListNumbers1.append(rd.randint(1,10000)) # fix: append each random element
ListNumbers1.sort() # sort the list, ascending order
List1 = ListNumbers1[-50:] # get last 50 elements of the list and assign it to List1
To search for the n biggest numbers in a list you need two procedures: one to find the biggest, the other to extract the n biggest.
You could also sort the list and take the n first, but this is not my approach because I needed to keep the original list and study it as is. For example, you could also know the offsets of each chosen number, which could be useful in some case.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
def n_biggest(lis,howmany):
#this function returns the biggest of a list with its offset
def biggest_in_list(lis):
n=0
biggest=0
offset=0
for item in lis:
n=n+1
if (item>biggest):
biggest=item
offset=n-1
return[biggest,offset]
#now this is the part where we create the descending list
image=lis#the use of an image will prevent finding twice the same number
result_list=[]
if len(lis)<howmany:#this will prevent errors if list is too small
howmany=len(lis)
for i in range(howmany):
find1=biggest_in_list(image)
result_list.append(find1[0])
image.pop(find1[1])
return result_list
print n_biggest([5,4,6,10,233,422],3)#this line was for testing the above
Hope this helps,
Regards,
import random as rd
List1 = sorted([rd.randint(1,10000) for j in range(1000)])[-50:]
Slice the last 50 elements of a sorted list comprehension, then you don't need ListNumbers1
using the itertools tool, I have all the possible permutations of a given list of numbers, but if the list is as follows:
List=[0,0,0,0,3,6,0,0,5,0,0]
itertools does not "know" that iterating the zeros is wasted work, for example the following iterations will appear in the results:
List=[0,3,0,0,0,6,0,0,5,0,0]
List=[0,3,0,0,0,6,0,0,5,0,0]
they are the same but itertools just takes the first zero ( for example ) and moves it at the fourth place in the list and vice-versa.
The question is: how can I iterate only some selected numbers and left alone others such like zero ? it can be with or without itertools.
Voilá - it works now - after getting the permutations on the "meat", I further get all possible combnations for the "0"s positions and yield
one permutation for each possible set of "0 positions" for each permutation
of the non-0s:
from itertools import permutations, combinations
def permut_with_pivot(sequence, pivot=0):
pivot_indexes = set()
seq_len = 0
def yield_non_pivots():
nonlocal seq_len
for i, item in enumerate(sequence):
if item != pivot:
yield item
else:
pivot_indexes.add(i)
seq_len = i + 1
def fill_pivots(permutation):
for pivot_positions in combinations(range(seq_len), len(pivot_indexes)):
sequence = iter(permutation)
yield tuple ((pivot if i in pivot_positions else next(sequence)) for i in range(seq_len))
for permutation in permutations(yield_non_pivots()):
for filled_permutation in fill_pivots(permutation):
yield filled_permutation
(I've used Python's 3 "nonlocal" keyword - if you are still on Python 2.7,
you will have to take another approach, like making seq_len be a list with a single item you can then repplace on the inner function)
My second try (the working one is actually the 3rd)
This is a naive approach that just keeps a cache of the already "seen" permutations - it saves on the work done to each permutation but notonthe work to generate all possible permutations:
from itertools import permutations
def non_repeating_permutations(seq):
seen = set()
for permutation in permutations(seq):
hperm = hash(permutation)
if hperm in seen:
continue
seen.add(hperm)
yield permutation
Append each result to a List. Now you'll have every single possible combination and then do the following:
list(set(your_big_list))
Set will narrow down the list down to only the unique permutations.
I'm not wholly sure if this is the problem you're trying to solve or you're worried about performance.
Regardless just made an account so I thought I'd try to contribute something
Your questions is unclear, but if you are trying to list the permutations without having 0 in your output, you can do it as follows:
from itertools import permutations
def perms( listy ):
return permutations( [i for i in listy if i!=0])
I want to create a list given two inputs, and under the condition that there cannot be any duplicates. The list should contain a random sequence of numbers. Then numbers in the list are positive integers.
Input 1: the length of the list (var samples)
Input 2: the highest number of the list (var end)
I know how to do this, but I want the list to contain a vast number of numbers, 1 million numbers, or more.
I have created 2 methods to solve this problem myself, both have their issues, on of them is slow the other produces a MemoryError.
Method 1, MemoryError:
import random
def create_lst_rand_int(end, samples):
if samples > end:
print('You cannot create this list')
else:
lst = []
lst_possible_values = range(0, end)
for item in range(0, samples):
random_choice = random.choice(lst_possible_values)
lst_possible_values.remove(random_choice)
lst.append(random_choice)
return lst
print create_lst_rand_int(1000000000000, 100000000001)
Method 2, slow:
import random
def lst_rand_int(end, samples):
lst = []
# lst cannot exist under these conditions
if samples > end:
print('List must be longer or equal to the highest value')
else:
while len(lst) < samples:
random_int = random.randint(0, end)
if not random_int in lst:
lst.append(random_int)
return lst
print lst_rand_int(1000000000000, 100000000001)
Since neither of my methods work well (method 1 does work better than method 2) I would like to know how I can create a list that meets my requirements better.
Try the solution given in the docs:
http://docs.python.org/2/library/random.html#random.sample
To choose a sample from a range of integers, use an xrange() object as an argument. This is especially fast and space efficient for sampling from a large population: sample(xrange(10000000), 60).
Or, in your case, random.sample(xrange(0,1000000000000), 100000000001)
This is still a giant data structure that may or may not fit in your memory. On my system:
>>> sys.getsizeof(1)
24
So 100000000001 samples will require 2400000000024 bytes, or roughly two terabytes. I suggest you find a way to work with smaller numbers of samples.
Try:
temp = xrange(end+1)
random.sample(temp, samples)
random.sample() does not pick any duplicates.
Since sample always returns a list, you're out of luck with such a large size. Try using a generator instead:
def rrange(min, max):
seen = set()
while len(seen) <= max - min:
n = random.randint(min, max)
if n not in seen:
seen.add(n)
yield n
This still requires memory to store seen elements, but at least not everything at once.
You could use a set instead of a list, and avoid checking for duplicates.
def lr2(end, samples):
lst = set()
# lst cannot exist under these conditions
if samples > end:
print('List must be longer or equal to the highest value')
else:
for _ in range(samples):
random_int = random.randint(0, end)
lst.add(random_int)
return lst
Since your sample size is such a large percentage of the items being sampled, a much faster approach is to shuffle the list of items and then just remove the first or last n items.
import random
def lst_rand_int(end, samples):
lst = range(0, end)
random.shuffle(lst)
return lst[0:samples]
If samples > end it will just return the whole list
If the list is too large for memory, you can break it into parts and store the parts on disc. In that case a random choice should be made to choose a section, then an item in the section and remove it for each sample required.