Ok, I have had a browse around and I have looking for either a C or python solution to this problem. I would prefer python...although it is my weaker language (of 2 very weak languages).
A set of numbers, such as 0 0 1 7 0 0 3 0 0 4
Find all permutations of the set.
The numbers >0 must stay in that order (NOT POSITION!)
There MUST be a 0 between numbers, a 0 is not required at the start and end of the set though. As long as there is AT LEAST ONE 0 between numbers >0.
So firstly, I thought of just finding all possible permutations and then removing the chaff (checking that if n>0 , !n+1>0) for each permutation and then the first number >0 == 1, 2nd # >0 ==7 etc. etc.
I then stopped and thought that was daft, say there were 12 numbers, that would give 12! permutations. This in the order of 500,000,000 permutations of which I would have to run through again to get rid of chaff.
Say I had 40-50 sets of these number sets to go through, that is a fair whack of time.
Is there a more logical way?
I thought of somehow having python do permutations somehow taking those rules in to account (if n>0, n+1 MUST == 0) and (n=first number, n2=2nd etc.)
An example of a smaller set would be (NOT ALL PERMUTATIONS, but gives idea):
1,2,3,0,0,0,0,0
1,0,2,0,3,0,0,0
0,1,0,2,0,3,0,0
0,0,1,0,2,0,3,0
0,0,1,0,0,2,0,3
0,1,0,0,2,0,3,0
etc. etc.
So 1,2,3 is in order but the "0"s are just shifted about?
Thanks!
Basically you want to reduce the number of combinations you have to compute by grouping things according to their invariants. Since the non-zero numbers must be in a fixed order let's start with that:
1 2 3
Since there must be 0's between them add them in
1 0 2 0 3
Now what you are left with is three 0's to place and you need to figure how many combinations give distinct sequences. Clearly from this example the possible positions you have are: before the 1, between the 1 and 2, between the 2 and 3 and after the 3. You have 4 positions in which to decide how to split up the remaining three 0's. This is a combination problem with repetition, for which the solution here is (3 + 4 - 1) Choose 3 (which is 20).
Hopefully the way that I went through this example problem is enough for you to generalize this to arbitrary sequences, so I will leave that as an exercise to the reader.
def find_permutations(l):
n = [e for e in l if e] # Strip zeros.
# Interspace non-zeros with zeros.
m = [j for i in n for j in (i,0)][:-1]
def fill(m):
if len(m) == len(l):
yield tuple(m)
else:
# Recursively fill with zeros.
for i in range(len(m)+1):
for o in fill(m[:i] + [0] + m[i:]):
yield tuple(o)
return sorted(set(fill(m)))
I think this should cover it. So for instance (in python 3), you could do:
>>> [print(p) for p in find_permutations([1,2,3,0,0,0,0,0])]
(0, 0, 0, 1, 0, 2, 0, 3)
(0, 0, 1, 0, 0, 2, 0, 3)
(0, 0, 1, 0, 2, 0, 0, 3)
(0, 0, 1, 0, 2, 0, 3, 0)
(0, 1, 0, 0, 0, 2, 0, 3)
(0, 1, 0, 0, 2, 0, 0, 3)
(0, 1, 0, 0, 2, 0, 3, 0)
(0, 1, 0, 2, 0, 0, 0, 3)
(0, 1, 0, 2, 0, 0, 3, 0)
(0, 1, 0, 2, 0, 3, 0, 0)
(1, 0, 0, 0, 0, 2, 0, 3)
(1, 0, 0, 0, 2, 0, 0, 3)
(1, 0, 0, 0, 2, 0, 3, 0)
(1, 0, 0, 2, 0, 0, 0, 3)
(1, 0, 0, 2, 0, 0, 3, 0)
(1, 0, 0, 2, 0, 3, 0, 0)
(1, 0, 2, 0, 0, 0, 0, 3)
(1, 0, 2, 0, 0, 0, 3, 0)
(1, 0, 2, 0, 0, 3, 0, 0)
(1, 0, 2, 0, 3, 0, 0, 0)
Was this similar to what you had in mind?
Edit: basically what the function called fill does is insert a zero between each number of the list, and recurse. Whenever enough numbers are recorded in the fill function (list length of recursively generated numbers equals list length of original input) a tuple of numbers is returned.
The only reason for converting to tuples when returning is that the type must be hashable to use in a set, as seen on the last line of the find_permutations function. sorted is for niceness.
Related
I got an array with bitwise encoded 3 channels.
like this:
1 for channel 1
2 for channel 2
3 for channel 1 and 2
4 for channel 3
5 for channel 1 and 3
6 for channel 3 and 2
I know how to do it in Matlab bitand(digital_word, 2^1) with bitwise and, but if I try to do the same for python with eg. for channel 1 np.bitwise_and(digital_word, 2^1) I get gibberish out
I want to get out a one for a given channel if the channel is encoded by the bit.
Some examples:
input:
array([0,0,1,0,1,0,3,4,5,6])
output:
channel 1: [0,0,1,0,1,0,1,0,1,0]
channel 2: [0,0,0,0,0,0,1,0,0,1]
channel 3: [0,0,0,0,0,0,0,1,1,1]
I'm not sure what you meant to achieve by using 2^1, but using np.bitwise_and was the correct approach.
For example, you get the result for channel 1 with np.bitwise_and(digital_word, 1):
>>> digital_word = np.array([0,0,1,0,1,0,3,4,5,6])
>>> np.bitwise_and(digital_word, 1)
array([0, 0, 1, 0, 1, 0, 1, 0, 1, 0])
For the higher-valued bits the result is almost what you want, but you need to right-shift it to get 1 instead of 2n.
>>> np.bitwise_and(digital_word, 2)
array([0, 0, 0, 0, 0, 0, 2, 0, 0, 2])
>>> np.bitwise_and(digital_word, 2) >> 1
array([0, 0, 0, 0, 0, 0, 1, 0, 0, 1])
Note that to get the third bit, you need to bitwise-and with 4 (= 23–1), not 3:
>>> np.bitwise_and(digital_word, 4)
array([0, 0, 0, 0, 0, 0, 0, 4, 4, 4])
>>> np.bitwise_and(digital_word, 4) >> 2
array([0, 0, 0, 0, 0, 0, 0, 1, 1, 1])
In general, to get the nth bit:
np.bitwise_and(digital_word, (1 << n)) >> n
NumPy arrays also support the & bitwise operator, so this is equivalent:
(digital_word & (1 << n)) >> n
A teacher is in the process of generating few reports based on the marks scored by the students of her class in a project based assessment.
Assume that the marks of her 10 students are available in a tuple. The marks are out of 25.
Write a python program to implement the following functions:
find_more_than_average(): Find and return the percentage of students who have scored more than the average mark of the class
sort_marks(): Sort the marks in the increasing order from 0 to 25. The sorted values should be populated in a list and returned
generate_frequency(): Find how many students have scored the same marks. For example, how many have scored 0, how many have scored 1, how many have scored 3….how many have scored 25. The result should be populated in a list and returned.
i got the average and sorted parts correct.but for the frequency, if the element is repeated twice i got the frequency as 1
list_of_marks=(12,18,25,24,2,5,18,20,20,21)
def find_more_than_average():
sumi=0
count=0
sumi=sum(list_of_marks)
avg=sumi/len(list_of_marks)
for i in list_of_marks:
if(i>avg):
count=count+1
morethanavg=(count/len(list_of_marks))*100
return morethanavg
#Remove pass and write your logic here
def sort_marks():
return sorted(list_of_marks)
#Remove pass and write your logic here
def generate_frequency():
#Remove pass and write your logic here
gener=[]
for i in range(0,26):
if i in list_of_marks:
gener.append(1)
else:
gener.append(0)
return gener
print(find_more_than_average())
print(generate_frequency())
print(sort_marks())
expected-[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 1, 1]
actual-[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1]
When you do:
if i in list_of_marks:
gener.append(1)
else:
gener.append(0)
it should be clear that you can never get a value other than 0 or 1. But you want the counts of those values not just a 1 indicating the value is in the list. One options is to create a list of zeros first, then step through the marks and add one to the index corresponding to the mark:
def generate_frequency():
gener = [0] * 26
for m in list_of_marks:
gener[m] += 1
return gener
Now when you see 20 twice you will increase generator[20] twice with the result:
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 1, 1]
I need to generate a two-dimensional python list. It would consist of 10 columns, with each column value being either '1' or '0'. Given these conditions, my list needs to be an exhaustive list of all the combinations that can be formed in this way. It'd naturally end up being 1024 rows long (2^10). However, I have no clue where to get started on this. Can anyone help?
So this is how I worked through this problem. First I saw that we wanted to loop over all 1024 combinations of 0s and 1s. This is essentially counting from 0 to 1023 in binary. So I made a for loop from 0 to 1023 and at each iteration, I converted the iteration variable i into binary with format(i, 'b') and then turned it into a list with the list method. In the case of a number like 1, this gets converted into ['1'] but we want to convert that into ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1'] which is what line
4 does. Finally, we append each result into the 'table' variable.
table=[]
for i in range(1024):
binaryRepresentation = list(format(i, 'b'))
finalRepresentation = ['0']*(10-len(binaryRepresentation)) + binaryRepresentation
table.append(finalRepresentation)
You can use combinations from itertools module, that can create a list of tuples, not a list of lists:
from itertools import combinations
# Generate all the combinations of 0 and 1
# in a list of tuples where each tuple is formed by 10 elements
# Which leads to 184756 combinations
gen_list = combinations([0,1]*10, 10)
# remove duplicates
unique_elements = list(set(gen_list))
# len(unique_elements)
# >>> 1024
An overview of the created list:
>>> unique_elements
[
(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
(0, 1, 0, 1, 0, 1, 0, 1, 0, 0)
...
(1, 1, 1, 0, 1, 0, 0, 1, 1, 1)
]
You should use numpy for this. For array creation, you could do:
import numpy as np
rows, cols = 1024, 10
arr = np.zeros((rows, cols))
Now, for setting certain values to 1 based on your condition, this could be used:
# this should be changed based on your needs
arr[arr > 0] = 1 # set all values greater than 0 to 1
If you need to create an array initialized with random binary data, you could do:
arr = np.random.randint(2, size=(rows,cols))
If performance isn't a concern, you could always count from 0 to 1023, create the string representation of that number in base 2 then convert to a list.
def binary_cols(n_cols):
for i in range(2**n_cols):
k = [int(j) for j in "{:b}".format(i)]
k = [0]*(n_cols - len(k)) + k
yield k
for col in binary_cols(10):
print col
gives
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
...
[1, 1, 1, 1, 1, 1, 1, 1, 0, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
print(len(list(binary_cols(10))))
1024
edit: I've just noticed that my answer is essentially a duplicate of Saleh Hindi's. Leaving mine here as there is a big enough difference in the specific tools used for the task, but their answer has a better explanation.
Suppose I have a 2D array (8x8) of 0's. I would like to fill this array with a predetermined number of 1's, but in a random manner. For example, suppose I want to place exactly 16 1's in the grid at random, resulting in something like this:
[[0, 0, 0, 1, 0, 0, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 1, 0, 0],
[0, 1, 0, 0, 0, 1, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 1]]
The resulting placement of the 1's does not matter in the slightest, as long as it is random (or as random as Python will allow).
My code technically works, but I imagine it's horrendously inefficient. All I'm doing is setting the probability of each number becoming a 1 to n/s, where n is the number of desired 1's and s is the size of the grid (i.e. number of elements), and then I check to see if the correct number of 1's was added. Here's the code (Python 2.7):
length = 8
numOnes = 16
while True:
board = [[(random.random() < float(numOnes)/(length**2))*1 for x in xrange(length)] for x in xrange(length)]
if sum([subarr.count(1) for subarr in board]) == 16:
break
print board
While this works, it seems like a roundabout method. Is there a better (i.e. more efficient) way of doing this? I foresee running this code many times (hundreds of thousands if not millions), so speed is a concern.
Either shuffle a list of 16 1s and 48 0s:
board = [1]*16 + 48*[0]
random.shuffle(board)
board = [board[i:i+8] for i in xrange(0, 64, 8)]
or fill the board with 0s and pick a random sample of 16 positions to put 1s in:
board = [[0]*8 for i in xrange(8)]
for pos in random.sample(xrange(64), 16):
board[pos//8][pos%8] = 1
I made the ones, made the zeros, concatenated them, shuffle them, and reshaped.
import numpy as np
def make_board(shape, ones):
o = np.ones(ones, dtype=np.int)
z = np.zeros(np.product(shape) - ones, dtype=np.int)
board = np.concatenate([o, z])
np.random.shuffle(board)
return board.reshape(shape)
make_board((8,8), 16)
Edit.
For what it's worth, user2357112's approach with numpy is fast...
def make_board(shape, ones):
size = np.product(shape)
board = np.zeros(size, dtype=np.int)
i = np.random.choice(np.arange(size), ones)
board[i] = 1
return board.reshape(shape)
Numpy has a library function, np.unpackbits, which will unpack a uint8 into a bit vector of length 8. Is there a correspondingly fast way to unpack larger numeric types? E.g. uint16 or uint32. I am working on a question that involves frequent translation between numbers, for array indexing, and their bit vector representations, and the bottleneck is our pack and unpack functions.
You can do this with view and unpackbits
Input:
unpackbits(arange(2, dtype=uint16).view(uint8))
Output:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
For a = arange(int(1e6), dtype=uint16) this is pretty fast at around 7 ms on my machine
%%timeit
unpackbits(a.view(uint8))
100 loops, best of 3: 7.03 ms per loop
As for endianness, you'll have to look at http://docs.scipy.org/doc/numpy/user/basics.byteswapping.html and apply the suggestions there depending on your needs.
This is the solution I use:
def unpackbits(x, num_bits):
if np.issubdtype(x.dtype, np.floating):
raise ValueError("numpy data type needs to be int-like")
xshape = list(x.shape)
x = x.reshape([-1, 1])
mask = 2**np.arange(num_bits, dtype=x.dtype).reshape([1, num_bits])
return (x & mask).astype(bool).astype(int).reshape(xshape + [num_bits])
This is a completely vectorized solution that works with any dimension ndarray and can unpack however many bits you want.
I have not found any function for this too, but maybe using Python's builtin struct.unpack can help make the custom function faster than shifting and anding longer uint (note that I am using uint64).
>>> import struct
>>> N = np.uint64(2 + 2**10 + 2**18 + 2**26)
>>> struct.unpack('>BBBBBBBB', N)
(2, 4, 4, 4, 0, 0, 0, 0)
The idea is to convert those to uint8, use unpackbits, concatenate the result. Or, depending on your application, it may be more convenient to use structured arrays.
There is also built-in bin() function, which produces string of 0s and 1s, but I am not sure how fast it is and it requires postprocessing too.
This works for arbitrary arrays of arbitrary uint (i.e. also for multidimensional arrays and also for numbers larger than the uint8 max value).
It cycles over the number of bits, rather than over the number of array elements, so it is reasonably fast.
def my_ManyParallel_uint2bits(in_intAr,Nbits):
''' convert (numpyarray of uint => array of Nbits bits) for many bits in parallel'''
inSize_T= in_intAr.shape
in_intAr_flat=in_intAr.flatten()
out_NbitAr= numpy.zeros((len(in_intAr_flat),Nbits))
for iBits in xrange(Nbits):
out_NbitAr[:,iBits]= (in_intAr_flat>>iBits)&1
out_NbitAr= out_NbitAr.reshape(inSize_T+(Nbits,))
return out_NbitAr
A=numpy.arange(256,261).astype('uint16')
# array([256, 257, 258, 259, 260], dtype=uint16)
B=my_ManyParallel_uint2bits(A,16).astype('uint16')
# array([[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]], dtype=uint16)