I need a vector that stores the median values of the medians of the main list "v". I have tried something with the following code but I am only able to write some values in the correct way.
v=[1,2,3,4,5,6,7,8,9,10]
final=[]
nfac=0
for j in range (0,4):
nfac=j+1
for k in range (0,nfac):
if k%2==0:
final.append(v[10/2**(nfac)-1])
else:
final.append(v[9-10/2**(nfac)])
The first median in v=[1,2,3,4,5,6,7,8,9,10] is 5
Then I want the medians of the remaining sublists [1,2,3,4] and [6,7,8,9,10]. I.e. 2 and 8 respectively. And so on.
The list "final" must be in the following form:
final=[5,2,8,1,3,6,9,4,7,10]
Please take a note that the task as you defined it is basically equivalent to constructing a binary heap from an array.
Definitely start by defining a helper function for finding the median:
def split_by_median(l):
median_ind = (len(l)-1) // 2
median = l[median_ind]
left = l[:median_ind]
right = l[median_ind+1:] if len(l) > 1 else []
return median, left, right
Following the example you give, you want to process the resulting sublists in a breadth-first manner, so we need a queue to remember the following tasks:
from collections import deque
def construct_heap(v):
lists_to_process = deque([sorted(v)])
nodes = []
while lists_to_process:
head = lists_to_process.popleft()
if len(head) == 0:
continue
median, left, right = split_by_median(head)
nodes.append(median)
lists_to_process.append(left)
lists_to_process.append(right)
return nodes
So calling the function finally:
print(construct_heap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) # [5, 2, 8, 1, 3, 6, 9, 4, 7, 10]
print(construct_heap([5, 1, 2])) # [2, 1, 5]
print(construct_heap([1, 0, 0.5, -1])) # [0, -1, 0.5, 1]
print(construct_heap([])) # []
Related
I currently have some code where I've created a mask which checks to see if a variable matches the first position in a sequence, called index_pos_overload. If it matches, the variable is chosen, and the check ends. However, I want to be able to use this mask to not only check if the number satisfies the condition of the mask, but if it doesn't move along to the next value in the sequence which does. It's essentially to pick out a row in my pandas data column, hyst. My code currently looks like this:
import pandas as pd
from itertools import chain
hyst = pd.DataFrame({"test":[12, 4, 5, 4, 1, 3, 2, 5, 10, 9, 7, 5, 3, 6, 3, 2 ,1, 5, 2]})
possible_overload_cycle = 1
index_pos_overload = chain.from_iterable((hyst.index[i])
for i in range(0, len(hyst)-1, 5))
if (possible_overload_cycle == index_pos_overload):
hyst_overload_cycle = possible_overload_cycle
else:
hyst_overload_cycle = 5 #next value in iterable where index_pos_overload is true
The expected output of hyst_overload_cycle should be this:
print(hyst_overload_cycle)
5
I've included my logic as to how I think this should work - possible_overload_cycle = 1 does not point to the first position in the dataframe, so hyst_overload_cycle should return as 5, the first position in the mask. I hope I've made sense, as I can't quite seem to work out how I would go about this programatically.
If I understood you correctly, it may be simpler than you think:
index_pos_overload can be an array / list, there is no need to use complex constructs to store a sequence of values
to find the first non-zero value from index_pos_overload, one can simply use np.nonzero()[0][0] (the first [0] is to select the dimension, the second is to select the index within that axis) and use array indexing of that on the original index_pos_overload array
The code would look like:
import numpy as np
import pandas as pd
hyst = pd.DataFrame({"test":[12, 4, 5, 4, 1, 3, 2, 5, 10, 9, 7, 5, 3, 6, 3, 2 ,1, 5, 2]})
possible_overload_cycle = 1
index_pos_overload = np.array([hyst.index[i] for i in range(0, len(hyst)-1, 5)])
if possible_overload_cycle in index_pos_overload:
hyst_overload_cycle = possible_overload_cycle
else:
hyst_overload_cycle = index_pos_overload[np.nonzero(index_pos_overload)[0][0]]
print(hyst_overload_cycle)
# 5
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 am trying to create a list of integers and then scan it in order to find the minimum absolute value of the substractions of the elements of the list. I have created the list, but there is problem in the code which finds the minimum absolute value, as the result it shows is not correct. I think it is probably in the possitions of the elements of the list during the loops. Can you help me find it?
For example, when I create a list Α = [2, 7, 5, 9, 3, 1, 2], the result of min should be 0, but it is 1.
Here is my code:
min=1000
for i in range (1, N-1):
for j in range (i+1, N):
if (abs (A [i-1] - A [j-1])<min):
min = abs (A [i-1] - A [j-1])
print ("%d" %min)
You can do it like this:
A = [2, 7, 5, 9, 3, 1, 2]
temp = sorted(A)
min_diff = min([abs(i - j) for i, j in zip(temp [:-1], temp [1:])])
print(min_diff) # -> 0
Sorting makes sure that the element pair (i, j) which produce the overall smallest difference would be a pair of consecutive elements. That makes the
number of checks you have to perform much less than the brute force approach of all possible combinations.
Something a bit more clever that short-circuits:
A = [2, 7, 5, 9, 3, 1, 2]
def find_min_diff(my_list):
if len(set(my_list)) != len(my_list): # See note 1
return 0
else:
temp = sorted(my_list)
my_min = float('inf')
for i, j in zip(temp [:-1], temp [1:]):
diff = abs(i - j)
if diff < my_min:
my_min = diff
return my_min
print(find_min_diff(A)) # -> 0
Notes:
1: Converting to set removes the duplicates so if the corresponding set has less elements than the original list it means that there is at least one duplicate value. But that necessarily means that the min absolute difference is 0 and we do not have to look any further.
I would be willing to bet that this is the fastest approach for all lists that would return 0.
You should not be subtracting 1 from j in the inner loop as you end up skipping the comparison of the last 2. It is better to make the adjustments in the loop ranges, rather than subtracting 1 (or not) in the loop code:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = 1000
for i in range (0, N-1):
for j in range (i+1, N):
if (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
I have also avoided the use of a built-in function name min.
To avoid the arbitrary, magic, number 1000, you can perform an initial check against None:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = None
for i in range (0, N-1):
for j in range (i+1, N):
if mint is None:
mint = abs(A[i] - A[j])
elif (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
This is a brute-force solution:
from itertools import combinations
A = [2, 7, 5, 9, 3, 1, 2]
min(abs(i-j) for i, j in combinations(A, 2)) # 0
using numpy
import numpy as np
A = [2, 7, 5, 9, 3, 1, 2]
v = np.abs(np.diff(np.sort(np.array(A))))
np.min(v)
out : 0
Or You can use numpy only for the diff part like this :
v = min(abs(np.diff(sorted(A))))
This is what you are looking for:
A = [2, 7, 5, 9, 3, 1, 2]
diffs = []
for index1, i in enumerate(A):
for index2, j in enumerate(A):
if index1 != index2:
diffs.append(abs(i-j))
print(min(diffs))
Output:
0
Updated to exclude subtraction of same items
This is question for my interview.
Write a recursive function that does the following:
Input: An array A of length N. N is an even number and N >= 2.
Output: A reordered array B. The first half of B contains A’s elements with even indices. The second half of B contains A’s elements with odd indices. Convention: the first index of an array is 0 (and thus it is an even number).
Input 1: [4, 8, 12, 16]
For this array, the indices and the values are as follows:
Index: 0, 1, 2, 3
Value: 4, 8, 12, 16
Thus, the output is as follows:
Expected output 1: [4, 12, 8, 16]
ADDITIONAL TEST CASE
Input 2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Expected output 2: [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
TASK
Write a recursive function in a programming language of your choice (as if you are writing real code to be used on a production server) for the above problem
In addition to the main function, you are free to write helper functions (if needed)
The code should have as few lines as possible (but it should still be clear and readable)
Note: Your recursive function must show the 'spirit' of a recursive function (not just the recursive form of a for loop)
Here is my code:
def slove(array, deep=0):
'''para:
array: list input.
return: list.
!!!Do not set value for deep!!!'''
if len(array) > 2:
if deep > 0:
for i in xrange(0, len(array), 2):
array[i], array[i + 1] = array[i + 1], array[i]
left = array[0]
right = array[-1]
array = array[1:-1]
array = slove(array, deep + 1)
array.insert(0, left)
array.append(right)
return array
else:
array[0], array[-1] = array[-1], array[0]
return array
if __name__ == '__main__':
array = map(int, raw_input('Enter array with sep is space key: ').split(' '))
# array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print slove(array)
He said that it is wrong because I use loop in program. He is correct? So how to solve it?
Why not just use slicing?
lst = [11,12,13,14,15,16]
lst[0::2] + lst[1::2]
Returns:
[11, 13, 15, 12, 14, 16]
This pseudocode function might help:
Let A[n] and B[n] be the 2 arrays where n is the size.
Then we will call the following method rearrange(0,0):
rearrange(int i, int j) {
b[j] = a[i];
b[j+n/2] = a[i+1];
if (j < n/2-1)
rearrange(i+2,j+1);
}
In this method, i jumps 2 times each therefore the odd items get stored in the first half of the output array. For the second half, j+n/2 saves the even items.
This is one (awkward) way to do it:
def even_odd_split(seq):
"""
>>> even_odd_split([4, 8, 12, 16])
[4, 12, 8, 16]
>>> even_odd_split([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
"""
assert(len(seq) % 2 == 0)
assert(len(seq) > 1)
def _split(seq):
if len(seq) == 0: return [], []
a, b = _split(seq[2:])
return [seq[0]] + a, [seq[1]] + b
a, b = _split(seq)
return a + b
if __name__ == '__main__':
import doctest
doctest.testmod()
I would solve it like this:
def f(l):
if len(l) == 1:
# only one element left
return l
if len(l) % 2 == 0:
# length is even
return l[:1] + f(l[1:])
else:
# length is odd
return f(l[1:]) + l[:1]
Every invocation of the function removes one element from the list and either puts it at the beginning or at the end of the resulting list.
It does not produce the given “expected” outputs, because the elements of the list appear in another order than they appear in the input list, but it matches the specification… and also, I think it’s pretty simple.
Really not sure where this fits. Say, I have a list:
>>>a = [1, 2, 3, 4, 5, 6, 7]
How can I iterate it in such a way, that it will check 4 first, then 5, then 3, then 6, and then 2(and so on for bigger lists)? I have only been able to work out the middle which is
>>>middle = [len(a)/2 if len(a) % 2 = 0 else ((len(a)+1)/2)]
I'm really not sure how to apply this, nor am I sure that my way of working out the middle is the best way. I've thought of grabbing two indexes and after each iteration, adding 1 and subtracting 1 from each respective index but have no idea how to make a for loop abide by these rules.
With regards as to why I need this; it's for analysing a valid play in a card game and will check from the middle card of a given hand up to each end until a valid card can be played.
You can just keep removing from the middle of list:
lst = range(1, 8)
while lst:
print lst.pop(len(lst)/2)
This is not the best solution performance-wise (removing item from list is expensive), but it is simple - good enough for a simple game.
EDIT:
More performance stable solution would be a generator, that calculates element position:
def iter_from_middle(lst):
try:
middle = len(lst)/2
yield lst[middle]
for shift in range(1, middle+1):
# order is important!
yield lst[middle - shift]
yield lst[middle + shift]
except IndexError: # occures on lst[len(lst)] or for empty list
raise StopIteration
To begin with, here is a very useful general purpose utility to interleave two sequences:
def imerge(a, b):
for i, j in itertools.izip_longest(a,b):
yield i
if j is not None:
yield j
with that, you just need to imerge
a[len(a) / 2: ]
with
reversed(a[: len(a) / 2])
You could also play index games, for example:
>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1]
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1, 8]
Here's a generator that yields alternating indexes for any given provided length. It could probably be improved/shorter, but it works.
def backNforth(length):
if length == 0:
return
else:
middle = length//2
yield middle
for ind in range(1, middle + 1):
if length > (2 * ind - 1):
yield middle - ind
if length > (2 * ind):
yield middle + ind
# for testing:
if __name__ == '__main__':
r = range(9)
for _ in backNforth(len(r)):
print(r[_])
Using that, you can just do this to produce a list of items in the order you want:
a = [1, 2, 3, 4, 5, 6, 7]
a_prime = [a[_] for _ in backNforth(len(a))]
In addition to the middle elements, I needed their index as well. I found Wasowski's answer very helpful, and modified it:
def iter_from_middle(lst):
index = len(lst)//2
for i in range(len(lst)):
index = index+i*(-1)**i
yield index, lst[index]
>>> my_list = [10, 11, 12, 13, 14, 15]
>>> [(index, item) for index, item in iter_from_middle(my_list)]
[(3, 13), (2, 12), (4, 14), (1, 11), (5, 15), (0, 10)]