Related
I have a binary list including only two elements(such as 0,1)
1010100010100000000000100000100000101000000000000000100000001000010
How to do paired transcoding with a custom setting of occurrence?
this is encoding rule:
if element occurs continuously less than 3 times, the encoding is 0,
if elements occurs continuously occurs 4-7 times, the encoding is 1,
if elements occurs continuously more than 7 times, the encoding is 2.
custom show up setting:
0-3 :0(short)
4-7 :1(medium)
more than 7 : 2(long)
for example :
how to let 0100111100011100000000 be transformed into [[0,0],[1,0],[0,0],[1,1],[0,0],[1,0],[0,2]] following by the above rule
*[a,b]
a: 0,1(there is only binary outcomes in my list )
b:0,1,2(it's my custom frequency setting)
The solution with only basic statements is:
word = '0100111100011100000000'
#Consecutive counts
count=1
counts = []
if len(word)>1:
for i in range(1,len(word)):
if word[i-1]==word[i]:
count+=1
else :
counts.append([ word[i-1],count])
count=1
counts.append([ word[i-1],count])
else:
i=0
counts.append([ word[i-1],count])
#check your conditions
output = []
for l in counts:
if l[1]<= 3 :
output.append([int(l[0]), 0])
elif l[1]> 3 and l[1]<8 :
output.append([int(l[0]), 1])
else:
output.append([int(l[0]), 2])
print(output)
Output :
[[0, 0], [1, 0], [0, 0], [1, 1], [0, 0], [1, 0], [0, 2]]
You can define a function to translate length of groups to numbers, then use e.g. itertools.groupby to separate the different groups of characters and apply that function is a list comprehension.
from itertools import groupby
def f(g):
n = len(list(g))
return 0 if n <= 3 else 1 if n <= 7 else 2
s = "0100111100011100000000"
res = [(int(k), f(g)) for k, g in groupby(s)]
# [(0, 0), (1, 0), (0, 0), (1, 1), (0, 0), (1, 0), (0, 2)]
I have an array and given an array of size N containing positive integers and I want to count number of smaller elements on right side of each array.
for example:-
Input:
N = 7
arr[] = {12, 1, 2, 3, 0, 11, 4}
Output: 6 1 1 1 0 1 0
Explanation: There are 6 elements right
after 12. There are 1 element right after
1. And so on.
And my code for this problem is like as :-
# python code here
n=int(input())
arr=list(map(int,input().split()))
ans=0
ANS=[]
for i in range(n-1):
for j in range(i+1,n):
if arr[i]>arr[j]:
ans+=1
ANS.append(ans)
ans=0
ANS.append(0)
print(ANS)
but the above my code take O(n^2) time complexity and I want to reduce the this. If anyone have any idea to reduce above python code time complexity please help me. Thank you.
This solution is O(n log(n)) as it is three iterations over the values and one sorting.
arr = [12, 1, 2, 3, 0, 11, 4]
# Gather original index and values
tups = []
for origin_index, el in enumerate(arr):
tups.append([origin_index, el])
# sort on value
tups.sort(key=lambda t: t[1])
res = []
for sorted_index, values in enumerate(tups):
# check the difference between the sorted and original index
# If there is a positive value we have the n difference smaller
# values to the right of this index value.
if sorted_index - values[0] > 0:
res.append([values[0], (sorted_index - values[0])])
elif sorted_index - values[0] == 0:
res.append([values[0], (sorted_index - values[0]) + 1])
else:
res.append([values[0], 0])
origin_sort_res = [0 for i in range(len(arr))]
for v in res:
# Return the from the sorted array to the original indexing
origin_sort_res[v[0]] = v[1]
print(origin_sort_res)
try this(nlog2n)
def solution(nums):
sortns = []
res = []
for n in reversed(nums):
idx = bisect.bisect_left(sortns, n)
res.append(idx)
sortns.insert(idx,n)
return res[::-1]
print(solution([12, 1, 2, 3, 0, 11, 4]))
# [6, 1, 1, 1, 0, 1, 0]
I have a simple code that generates a list of random numbers.
x = [random.randrange(0,11) for i in range(10)]
The problem I'm having is that, since it's random, it sometimes produces duplicate numbers right next to each other. How do I change the code so that it never happens? I'm looking for something like this:
[1, 7, 2, 8, 7, 2, 8, 2, 6, 5]
So that every time I run the code, all the numbers that are next to each other are different.
x = []
while len(x) < 10:
r = random.randrange(0,11)
if not x or x[-1] != r:
x.append(r)
x[-1] contains the last inserted element, which we check not to be the same as the new random number. With not x we check that the array is not empty, as it would generate a IndexError during the first iteration of the loop
Here's an approach that doesn't rely on retrying:
>>> import random
>>> x = [random.choice(range(12))]
>>> for _ in range(9):
... x.append(random.choice([*range(x[-1]), *range(x[-1]+1, 12)]))
...
>>> x
[6, 2, 5, 8, 1, 8, 0, 4, 6, 0]
The idea is to choose each new number by picking from a list that excludes the previously picked number.
Note that having to re-generate a new list to pick from each time keeps this from actually being an efficiency improvement. If you were generating a very long list from a relatively short range, though, it might be worthwhile to generate different pools of numbers up front so that you could then select from the appropriate one in constant time:
>>> pool = [[*range(i), *range(i+1, 3)] for i in range(3)]
>>> x = [random.choice(random.choice(pool))]
>>> for _ in range(10000):
... x.append(random.choice(pool[x[-1]]))
...
>>> x
[0, 2, 0, 2, 0, 2, 1, 0, 1, 2, 0, 1, 2, 1, 0, ...]
O(n) solution by adding to the last element randomly from [1,stop) modulo stop
import random
x = [random.randrange(0,11)]
x.extend((x[-1]+random.randrange(1,11)) % 11 for i in range(9))
x
Output
[0, 10, 4, 5, 10, 1, 4, 8, 0, 9]
from random import randrange
from itertools import islice, groupby
# Make an infinite amount of randrange's results available
pool = iter(lambda: randrange(0, 11), None)
# Use groupby to squash consecutive values into one and islice to at most 10 in total
result = [v for v, _ in islice(groupby(pool), 10)]
Function solution that doesn't iterate to check for repeats, just checks each add against the last number in the list:
import random
def get_random_list_without_neighbors(lower_limit, upper_limit, length):
res = []
# add the first number
res.append(random.randrange(lower_limit, upper_limit))
while len(res) < length:
x = random.randrange(lower_limit, upper_limit)
# check that the new number x doesn't match the last number in the list
if x != res[-1]:
res.append(x)
return res
>>> print(get_random_list_without_neighbors(0, 11, 10)
[10, 1, 2, 3, 1, 8, 6, 5, 6, 2]
def random_sequence_without_same_neighbours(n, min, max):
x = [random.randrange(min, max + 1)]
uniq_value_count = max - min + 1
next_choises_count = uniq_value_count - 1
for i in range(n - 1):
circular_shift = random.randrange(0, next_choises_count)
x.append(min + (x[-1] + circular_shift + 1) % uniq_value_count)
return x
random_sequence_without_same_neighbours(n=10, min=0, max=10)
It's not to much pythonic but you can do something like this
import random
def random_numbers_generator(n):
"Generate a list of random numbers but without two duplicate numbers in a row "
result = []
for _ in range(n):
number = random.randint(1, n)
if result and number == result[-1]:
continue
result.append(number)
return result
print(random_numbers_generator(10))
Result:
3, 6, 2, 4, 2, 6, 2, 1, 4, 7]
I'm trying to find a way, using built-in functions, to list every way to organize N balls in M slots. The balls can stack in the slots. For example:
N = 2, M = 3 -> {|0|1|1|, |1|0|1|, |1|1|0|, |2|0|0|, |0|2|0|, |0|0|2|}
itertools.permutations() is part of the puzzle, but how can you go through all possible stacks of balls that preserves N?
Let oo represent two balls.
The problem of placing 2 balls in 3 slots is equivalent to the problem of placing 2 balls around 2 sticks:
|o|o --> 0,1,1
o||o 1,0,1
o|o| 1,1,0
oo|| 2,0,0
|oo| 0,2,0
||oo 0,0,2
The sticks, | represent the edges of the slots. The number of balls in each slot is shown on the right.
Notice that in each row there are 4 locations, and 2 sticks. There is always one fewer stick than there are slots. So the problem is equivalent to finding all the ways to select 2 locations for the balls out of 4 possibilities. 4 choose 2.
In [98]: import itertools as IT
In [99]: list(IT.combinations(range(4), 2))
Out[99]: [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
These, then, are the possible locations for the balls.
All that's left to do is to compute into which slot these balls belong. Let's take (1, 3) as an example. The pictoral diagram for (1, 3) looks like this:
|o|o
It turns out that if you subtract (0, 1) elementwise from (1, 3), you get the slot for each ball:
(1, 3)
(0, 1)
------
(1, 2)
Thus, the first ball is in slot 1, the second in slot 2.
In general, if you subtract range(m-1) from the combination, you get the slot values. This makes some sense if you think of the amount you are subtracting as the number of balls that precede the current ball in the pictoral diagram. Since our diagrams consist of balls and slots, if you subtract the balls, what remains are slots.
import itertools as IT
def pigeonhole(n, m):
"""
Generate the ways n balls can placed in m slots
"""
for choice in IT.combinations(range(n+m-1), n):
slot = [c-i for i,c in enumerate(choice)]
result = [0]*m
for i in slot:
result[i] += 1
yield result
print(list(pigeonhole(2,3)))
yields
[[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]]
To find all assignments of N balls to M slots:
if N is 0 then
leave all M slots empty
otherwise, if M is 1, then
put all N balls to the only slot
otherwise
For each i in 0 .. N
put i balls in M-th slot, and
find all assignments of remaining N-i balls to remaining M-1 slots
Oh, here's a fun way to come at it:
>>> import random
>>> def permutate(N, M, lim = 1e6):
... for i in range(int(lim)):
... tup = ()
... for j in range(M):
... tup += (random.randrange(0,N+1),)
...
... if sum(tup) == N: yield tup
...
>>> permutes = []
>>> for p in permutate(2, 3):
... if not p in permutes:
... permutes.append(p)
...
>>> permutes
[(0, 1, 1), (0, 0, 2), (2, 0, 0), (0, 2, 0), (1, 0, 1), (1, 1, 0)]
>>>
First we create a generator that gives a valid tuple of M elements which sums to N. We do this in a Monte Carlo-esk approach by composing each element of of a random number from 0 to N+1. We do this M times, and append each guess to a tuple. We then check if the tuple is valid (sums to N). We then call this generator repeatedly until it is exhausted, and add non-repeat entries to a list.
Some Things to Note:
You'll need to tune lim to be appropriate for what you need. Generally it should be higher for larger M and N. You could modify this (with some effort) to estimate if lim is sized appropriate since you can figure how long permutes should be based off of N and M.
Monte Carlo methods are slow, which is why I categorized this as a "fun" approach
Consider using itertools.combinations_with_replacement.
You can easily do like this.
import itertools
def myfunc(n, m):
for j in itertools.combinations_with_replacement(xrange(m), n):
r = [0] * m
for i in j:
r[i] += 1
yield r
The problem is how to ensure this is correct.
I think #wnnmaw answer can be useful for that, because the logic is very simple.
#http://stackoverflow.com/a/22940260/2931409
import random
def permutate(N, M, lim = 1e6):
for i in range(int(lim)):
tup = []#<--Sorry changed here for test
for j in range(M):
tup += (random.randrange(0,N+1),)
if sum(tup) == N: yield tup
def perm(n, m):
permutes = []
for p in permutate(n, m):
if not p in permutes:
permutes.append(p)
return permutes
OK. Now check myfunc correctly works.
>>> N, M = 3, 5
>>> sorted(myfunc(N, M)) == sorted(perm(N, M))
True
Here's a nice way to do it.
NI = sum(in_pop)#number of input balls
# create the seed vector to be folded
u0 = [0] * NO
for i in range(NI):
u0[i] = 1
# create a storage basis matrix and fold the seed vector
basis = [u0]
ui = []
for i in arange(1,NI):
# copy the last vector
ui = basis[i - 1][:]
# find the number to 0 boundary
edge = ui.index(0)
# set the previous value to zero
tmp = ui[edge - 1]
ui[edge - 1] = 0
# increment the value behind that
ui[edge - 2] = ui[edge - 2] + tmp
print 'edge # ', edge
print 'ui', ui
basis.append(ui[:])
print basis
# run through the permutations in this basis
orderings = []
for ui in basis:
perms = set(itertools.permutations(ui))
orderings.extend(perms)
print orderings
The result is the following for input N=2, M=3:
edge # 2
ui [2, 0, 0]
[[1, 1, 0], [2, 0, 0]]
[(0, 1, 1), (1, 1, 0), (1, 0, 1), (0, 2, 0), (2, 0, 0), (0, 0, 2)]
[Finished in 0.5s]
I'd like to do a random shuffle of a list but with one condition: an element can never be in the same original position after the shuffle.
Is there a one line way to do such in python for a list?
Example:
list_ex = [1,2,3]
each of the following shuffled lists should have the same probability of being sampled after the shuffle:
list_ex_shuffled = [2,3,1]
list_ex_shuffled = [3,1,2]
but the permutations [1,2,3], [1,3,2], [2,1,3] and [3,2,1] are not allowed since all of them repeat one of the elements positions.
NOTE: Each element in the list_ex is a unique id. No repetition of the same element is allowed.
Randomize in a loop and keep rejecting the results until your condition is satisfied:
import random
def shuffle_list(some_list):
randomized_list = some_list[:]
while True:
random.shuffle(randomized_list)
for a, b in zip(some_list, randomized_list):
if a == b:
break
else:
return randomized_list
I'd describe such shuffles as 'permutations with no fixed points'. They're also known as derangements.
The probability that a random permutation is a derangement is approximately 1/e (fun to prove). This is true however long the list. Thus an obvious algorithm to give a random derangement is to shuffle the cards normally, and keep shuffling until you have a derangement. The expected number of necessary shuffles is about 3, and it's rare you'll have to shuffle more than ten times.
(1-1/e)**11 < 1%
Suppose there are n people at a party, each of whom brought an umbrella. At the end of the party, each person takes an umbrella at random from the basket. What is the probability that no-one holds their own umbrella?
You could generate all possible valid shufflings:
>>> list_ex = [1,2,3]
>>> import itertools
>>> list(itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
... itertools.permutations(list_ex, len(list_ex))))
[(2, 3, 1), (3, 1, 2)]
For some other sequence:
>>> list_ex = [7,8,9,0]
>>> list(itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
... itertools.permutations(list_ex, len(list_ex))))
[(8, 7, 0, 9), (8, 9, 0, 7), (8, 0, 7, 9), (9, 7, 0, 8), (9, 0, 7, 8), (9, 0, 8, 7), (0, 7, 8, 9), (0, 9, 7, 8), (0, 9, 8, 7)]
You could also make this a bit more efficient by short-circuiting the iterator if you just want one result:
>>> list_ex = [1,2,3]
>>> i = itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
... itertools.permutations(list_ex, len(list_ex)))
>>> next(i)
(2, 3, 1)
But, it would not be a random choice. You'd have to generate all of them and choose one for it to be an actual random result:
>>> list_ex = [1,2,3]
>>> i = itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
... itertools.permutations(list_ex, len(list_ex)))
>>> import random
>>> random.choice(list(i))
(2, 3, 1)
Here is another take on this. You can pick one solution or another depending on your needs. This is not a one liner but shuffles the indices of elements instead of the elements themselves. Thus, the original list may have duplicate values or values of types that cannot be compared or may be expensive to compare.
#! /usr/bin/env python
import random
def shuffled_values(data):
list_length = len(data)
candidate = range(list_length)
while True:
random.shuffle(candidate)
if not any(i==j for i,j in zip(candidate, range(list_length))):
yield [data[i] for i in candidate]
list_ex = [1, 2, 3]
list_gen = shuffled_values(list_ex)
for i in range(0, 10):
print list_gen.next()
This gives:
[2, 3, 1]
[3, 1, 2]
[3, 1, 2]
[2, 3, 1]
[3, 1, 2]
[3, 1, 2]
[2, 3, 1]
[2, 3, 1]
[3, 1, 2]
[2, 3, 1]
If list_ex is [2, 2, 2], this method will keep yielding [2, 2, 2] over and over. The other solutions will give you empty lists. I am not sure what you want in this case.
Use Knuth-Durstenfeld to shuffle the list. As long as it is found to be in the original position during the shuffling process, a new shuffling process is started from the beginning until it returns to a qualified arrangement. The time complexity of this algorithm is the smallest constant term:
def _random_derangement(x: list, randint: Callable[[int, int], int]) -> None:
'''
Random derangement list x in place, and return None.
An element can never be in the same original position after the shuffle. provides uniform distribution over permutations.
The formal parameter randint requires a callable object such as rand_int(b, a) that generates a random integer within the specified closed interval.
'''
from collections import namedtuple
sequence_type = namedtuple('sequence_type', ('sequence_number', 'elem'))
x_length = len(x)
if x_length > 1:
for i in range(x_length):
x[i] = sequence_type(sequence_number = i, elem = x[i])
end_label = x_length - 1
while True:
for i in range(end_label, 0, -1):
random_location = randint(i, 0)
if x[random_location].sequence_number != i:
x[i], x[random_location] = x[random_location], x[i]
else:
break
else:
if x[0].sequence_number != 0: break
for i in range(x_length):
x[i] = x[i].elem
complete_shuffle
Here's another algorithm. Take cards at random. If your ith card is card i, put it back and try again. Only problem, what if when you get to the last card it's the one you don't want. Swap it with one of the others.
I think this is fair (uniformally random).
import random
def permutation_without_fixed_points(n):
if n == 1:
raise ArgumentError, "n must be greater than 1"
result = []
remaining = range(n)
i = 0
while remaining:
if remaining == [n-1]:
break
x = i
while x == i:
j = random.randrange(len(remaining))
x = remaining[j]
remaining.pop(j)
result.append(x)
i += 1
if remaining == [n-1]:
j = random.randrange(n-1)
result.append(result[j])
result[j] = n
return result