How to sort 4 integers using only min() and max()? Python - python-3.x

I am trying to sort 4 integers input by the user into numerical order using only the min() and max() functions in python. I can get the highest and lowest number easily, but cannot work out a combination to order the two middle numbers? Does anyone have an idea?

So I'm guessing your input is something like this?
string = input('Type your numbers, separated by a space')
Then I'd do:
numbers = [int(i) for i in string.strip().split(' ')]
amount_of_numbers = len(numbers)
sorted = []
for i in range(amount_of_numbers):
x = max(numbers)
numbers.remove(x)
sorted.append(x)
print(sorted)
This will sort them using max, but min can also be used.
If you didn't have to use min and max:
string = input('Type your numbers, separated by a space')
numbers = [int(i) for i in string.strip().split(' ')]
numbers.sort() #an optional reverse argument possible
print(numbers)

LITERALLY just min and max? Odd, but, why not. I'm about to crash, but I think the following would work:
# Easy
arr[0] = max(a,b,c,d)
# Take the smallest element from each pair.
#
# You will never take the largest element from the set, but since one of the
# pairs will be (largest, second_largest) you will at some point take the
# second largest. Take the maximum value of the selected items - which
# will be the maximum of the items ignoring the largest value.
arr[1] = max(min(a,b)
min(a,c)
min(a,d)
min(b,c)
min(b,d)
min(c,d))
# Similar logic, but reversed, to take the smallest of the largest of each
# pair - again omitting the smallest number, then taking the smallest.
arr[2] = min(max(a,b)
max(a,c)
max(a,d)
max(b,c)
max(b,d)
max(c,d))
# Easy
arr[3] = min(a,b,c,d)

For Tankerbuzz's result for the following:
first_integer = 9
second_integer = 19
third_integer = 1
fourth_integer = 15
I get 1, 15, 9, 19 as the ascending values.
The following is one of the forms that gives symbolic form of the ascending values (using i1-i4 instead of first_integer, etc...):
Min(i1, i2, i3, i4)
Max(Min(i4, Max(Min(i1, i2), Min(i3, Max(i1, i2))), Max(i1, i2, i3)), Min(i1, i2, i3, Max(i1, i2)))
Max(Min(i1, i2), Min(i3, Max(i1, i2)), Min(i4, Max(i1, i2, i3)))
Max(i1, i2, i3, i4)
It was generated by a 'bubble sort' using the Min and Max functions of SymPy (a python CAS):
def minmaxsort(v):
"""return a sorted list of the elements in v using the
Min and Max functions.
Examples
========
>>> minmaxsort(3, 2, 1)
[1, 2, 3]
>>> minmaxsort(1, x, y)
[Min(1, x, y), Max(Min(1, x), Min(y, Max(1, x))), Max(1, x, y)]
>>> minmaxsort(1, y, x)
[Min(1, x, y), Max(Min(1, y), Min(x, Max(1, y))), Max(1, x, y)]
"""
from sympy import Min, Max
v = list(v)
v0 = Min(*v)
for j in range(len(v)):
for i in range(len(v) - j - 1):
w = v[i:i + 2]
v[i:i + 2] = [Min(*w), Max(*w)]
v[0] = v0
return v

I have worked it out.
min_integer = min(first_integer, second_integer, third_integer, fourth_integer)
mid_low_integer = min(max(first_integer, second_integer), max(third_integer, fourth_integer))
mid_high_integer = max(min(first_integer, second_integer), min(third_integer, fourth_integer))
max_integer = max(first_integer, second_integer, third_integer, fourth_integer)

Related

Rotate String to find Hamming distance equal to K

We are given 2 binary strings (A and B) both of length N and an integer K.
We need to check if there is a rotation of string B present where hamming distance between A and the rotated string is equal to K. We can just remove one character from front and put it at back in single operation.
Example : Let say we are given these 2 string with values as A="01011" and B="01110" and also K=4.
Note : Hamming distance between binary string is number of bit positions in which two corresponding bits in strings are different.
In above example answer will be "YES" as if we rotate string B once it becomes "11100", which has hamming distance of 4, that is equal to K.
Approach :
For every rotated string of B
check that hamming distance with A
if hamming distance == K:
return "YES"
return "NO"
But obviously above approach will execute in O(Length of string x Length of string) times. Is there better approach to solve this. As we don't need to find the actual string, I am just wondering there is some better algorithm to get this answer.
Constraints :
Length of each string <= 2000
Number of test cases to run in one file <=600
First note that we can compute the Hamming distance as the sum of a[i]*(1-b[i]) + b[i]*(1-a[i]) for all i. This simplifies to a[i] + b[i] - 2*a[i]*b[i]. Now in O(n) we can compute the sum of a[i] and b[i] for all i, and this doesn't change with bit rotations, so the only interesting term is 2*a[i]*b[i]. We can compute this term efficiently for all bit rotations by noting that it is equivalent to a circular convolution of a and b. We can efficiently compute such convolutions using the Discrete Fourier transform in O(n log n) time.
For example in Python using numpy:
import numpy as np
def hdist(a, b):
return sum(bool(ai) ^ bool(bi) for ai, bi in zip(a, b))
def slow_circular_hdist(a, b):
return [hdist(a, b[i:] + b[:i]) for i in range(len(b))]
def circular_convolution(a, b):
return np.real(np.fft.ifft(np.fft.fft(a)*np.fft.fft(b[::-1])))[::-1]
def fast_circular_hdist(a, b):
hdist = np.sum(a) + np.sum(b) - 2*circular_convolution(a, b)
return list(np.rint(hdist).astype(int))
Usage:
>>> a = [0, 1, 0, 1, 1]
>>> b = [0, 1, 1, 1, 0]
>>> slow_circular_hdist(a, b)
[2, 4, 2, 2, 2]
>>> fast_circular_hdist(a, b)
[2, 4, 2, 2, 2]
Speed and large correctness test:
>>> x = list((np.random.random(5000) < 0.5).astype(int))
>>> y = list((np.random.random(5000) < 0.5).astype(int))
>>> s = time.time(); slow_circular_hdist(x, y); print(time.time() - s)
6.682933807373047
>>> s = time.time(); fast_circular_hdist(x, y); print(time.time() - s)
0.008500814437866211
>>> slow_circular_hdist(x, y) == fast_circular_hdist(x, y)
True

Pythonic way of binning data without pandas/numpy

I'm looking for a way to bin a dataset of several hundred entries into 20 bins. But without the use of big modules like pandas (cut) and numpy (digitize).
Can anyone think of a better solution than 18 elifs?
All you need to do is figure out which bin each element is in. That is fairly trivial given the size of bins, if they're uniform. From your array, you can find the minval and maxval. Then, binwidth = (maxval - minval) / nbins. For an element of your array elem, and a known minimum value minval and bin width binwidth, the element will fall in bin number int((elem - minval) / binwidth). This leaves the edge case where elem == maxval. In this case, the bin number is equal to nbins (the nbins + 1th bin, because python is zero-based), so we have to decrement the bin number for just that one case.
So we can write a function that does this:
import random
def splitIntoBins(arr, nbins, minval=None, maxval=None):
minval = min(arr) if minval is None else minval # Select minval if specified, otherwise min of data
maxval = max(arr) if maxval is None else maxval # Same for maxval
binwidth = (maxval - minval) / nbins # Bin width
allbins = [[] for _ in range(nbins)] # Pre-make a list-of-lists to hold values
for elem in arr:
binnum = int((elem - minval) // binwidth) # Find which bin this element belongs in
binindex = min(nbins-1, binnum) # To handle the case of elem == maxval
allbins[binindex].append(elem) # Add this element to the bin
return allbins
# Make 1000 random numbers between 0 and 1
x = [random.random() for _ in range(1000)]
# split into 10 bins from 0 to 1, i.e. a bin every 0.1
b = splitIntoBins(x, 10, 0, 1)
# Get min, max, count for each bin
counts = [(min(v), max(v), len(v)) for v in b]
print(counts)
This gives
[(0.00017731201786974626, 0.09983758434153, 101),
(0.10111204267013452, 0.19959594179848794, 97),
(0.20089309189822557, 0.2990120768922335, 100),
(0.3013915797055913, 0.39922131591077614, 90),
(0.4009006835799309, 0.49969892298935836, 83),
(0.501675740585966, 0.5999729295882031, 119),
(0.6010149249108184, 0.7000366124696699, 120),
(0.7008002068562794, 0.7970568220766774, 91),
(0.8018697850229161, 0.8990963218226316, 99),
(0.9000732426223624, 0.9967964437788829, 100)]
Which looks like what we expect.
For non-uniform bins, it is no longer an arithmetic calculation. In this case, the element elem is in the bin that has a lower bound smaller than elem, and the an upper bound larger than elem.
def splitIntoBins2(arr, bins):
binends = bins[1:]
binstarts = bins[:-1]
allbins = [[] for _ in binends] # Pre-make a list-of-lists to hold values
for elem in arr:
for i, (lower_bound, upper_bound) in enumerate(zip(binstarts, binends)):
if upper_bound >= elem and lower_bound <= elem:
allbins[i].append(elem) # Add this element to the bin
break
return allbins

Round a number to a given set of values [duplicate]

This question already has answers here:
From list of integers, get number closest to a given value
(10 answers)
Closed 5 years ago.
Talking Python 3 here.
I'm looking to round a number to a given set of values which can vary
Assume value_set = [x, y, z] and for the sake of the example x, y, z = 1, 3.12, 4 I'm looking for a function that will round a given float to the closest number
custom_round(0) --> 1
custom_round(2.7) --> 3.12
Notice that it should be generic enough that value_set length will vary also
You can use the min function in order to find the minimum in your list when the key is the absolute value of x-n (x is each item in the list).
value_set = [1, 3.12, 4]
def return_closest(n):
return min(value_set, key=lambda x:abs(x-n))
number_to_check = 3
print (return_closest(number_to_check))
>>> 3.12
You can do this by first sorting the list, and then use binary search:
from bisect import bisect_left
class CustomRound:
def __init__(self,iterable):
self.data = sorted(iterable)
def __call__(self,x):
data = self.data
ndata = len(data)
idx = bisect_left(data,x)
if idx <= 0:
return data[0]
elif idx >= ndata:
return data[ndata-1]
x0 = data[idx-1]
x1 = data[idx]
if abs(x-x0) < abs(x-x1):
return x0
return x1
You can than construct your CustomRound like:
values = [1,3.12,4]
custom_round = CustomRound(values)
and simply call it:
>>> custom_round(0)
1
>>> custom_round(0.5)
1
>>> custom_round(1.5)
1
>>> custom_round(2.5)
3.12
>>> custom_round(3.12)
3.12
>>> custom_round(3.9)
4
>>> custom_round(4.1)
4
>>> custom_round(4.99)
4
This approach will work in O(log n) for rounding and O(n log n) for construction. So you will invest some additional time to construct the custom_round, but if you call it often, it will eventually pay off in rounding individual numbers.

Permutation for equation solving

If there is an equation 3a + 6b +7d = 55 and the solution set is {1,4,6} but it is unknown which number in the solution corresponds to which variable, is there a way to determine which number corresponds with which variable without using brute force? Could this method scale if the equation had 1000 variables? Thanks!
This is brute-force solution with pruning search where solution can't be found.
Let's show two things. First, if coefficients and solutions are non-negative numbers and if they are represented as a sorted list, then maximal value equation can have is 'parallel sum', and minimal value is 'reversed sum'.
max = sum(c*s for c, s in zip(coeffs, sols))
min = sum(c*s for c, s in zip(coeffs, reversed(sols)))
It is enough to see that for four numbers 0 <= a1 <= a2 and 0 <= b1 <= b2 holds:
a1*b1 + a2*b2 = a1*b2 + a2*b1 + (a2-a1)*(b2-b1) >= a1*b2 + a2*b1.
Second is that it is always possible to transform problem to problem of the same type with non-negative coefficients and solutions. To 'move' solutions to non-negative it is needed to add to all solutions value -min(solutions) and to result -min(solutions)*sum(coefficients).
Similar procedure 'moves' coefficients to non-negative.
Here is python implementation of solution:
def C(coeffs, res, sols):
_max = sum(i*j for i, j in zip(coeffs, sols))
if _max < res: # No result
return None
if _max == res: # Result mapping coeffs <-> sols
return sols
_min = sum(i*j for i, j in zip(coeffs, reversed(sols)))
if _min > res: # No result
return None
if _min == res: # Result mapping coeffs <-> reversed sols
return sols[::-1] # reverse sols
# For next coefficient try all solutions
for i, s in enumerate(sols):
r = C(coeffs[1:], res - coeffs[0]*s, sols[:i] + sols[(i+1):])
if r is not None:
return [s] + r
print C([3, 6, 7], 55, [1, 4, 6])

String concatenation queries

I have a list of characters, say x in number, denoted by b[1], b[2], b[3] ... b[x]. After x,
b[x+1] is the concatenation of b[1],b[2].... b[x] in that order. Similarly,
b[x+2] is the concatenation of b[2],b[3]....b[x],b[x+1].
So, basically, b[n] will be concatenation of last x terms of b[i], taken left from right.
Given parameters as p and q as queries, how can I find out which character among b[1], b[2], b[3]..... b[x] does the qth character of b[p] corresponds to?
Note: x and b[1], b[2], b[3]..... b[x] is fixed for all queries.
I tried brute-forcing but the string length increases exponentially for large x.(x<=100).
Example:
When x=3,
b[] = a, b, c, a b c, b c abc, c abc bcabc, abc bcabc cabcbcabc, //....
//Spaces for clarity, only commas separate array elements
So for a query where p=7, q=5, answer returned would be 3(corresponding to character 'c').
I am just having difficulty figuring out the maths behind it. Language is no issue
I wrote this answer as I figured it out, so please bear with me.
As you mentioned, it is much easier to find out where the character at b[p][q] comes from among the original x characters than to generate b[p] for large p. To do so, we will use a loop to find where the current b[p][q] came from, thereby reducing p until it is between 1 and x, and q until it is 1.
Let's look at an example for x=3 to see if we can get a formula:
p N(p) b[p]
- ---- ----
1 1 a
2 1 b
3 1 c
4 3 a b c
5 5 b c abc
6 9 c abc bcabc
7 17 abc bcabc cabcbcabc
8 31 bcabc cabcbcabc abcbcabccabcbcabc
9 57 cabcbcabc abcbcabccabcbcabc bcabccabcbcabcabcbcabccabcbcabc
The sequence is clear: N(p) = N(p-1) + N(p-2) + N(p-3), where N(p) is the number of characters in the pth element of b. Given p and x, you can just brute-force compute all the N for the range [1, p]. This will allow you to figure out which prior element of b b[p][q] came from.
To illustrate, say x=3, p=9 and q=45.
The chart above gives N(6)=9, N(7)=17 and N(8)=31. Since 45>9+17, you know that b[9][45] comes from b[8][45-(9+17)] = b[8][19].
Continuing iteratively/recursively, 19>9+5, so b[8][19] = b[7][19-(9+5)] = b[7][5].
Now 5>N(4) but 5<N(4)+N(5), so b[7][5] = b[5][5-3] = b[5][2].
b[5][2] = b[3][2-1] = b[3][1]
Since 3 <= x, we have our termination condition, and b[9][45] is c from b[3].
Something like this can very easily be computed either recursively or iteratively given starting p, q, x and b up to x. My method requires p array elements to compute N(p) for the entire sequence. This can be allocated in an array or on the stack if working recursively.
Here is a reference implementation in vanilla Python (no external imports, although numpy would probably help streamline this):
def so38509640(b, p, q):
"""
p, q are integers. b is a char sequence of length x.
list, string, or tuple are all valid choices for b.
"""
x = len(b)
# Trivial case
if p <= x:
if q != 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
return p, b[p - 1]
# Construct list of counts
N = [1] * p
for i in range(x, p):
N[i] = sum(N[i - x:i])
print('N =', N)
# Error check
if q > N[-1]:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
print('b[{}][{}]'.format(p, q), end='')
# Reduce p, q until it is p < x
while p > x:
# Find which previous element character q comes from
offset = 0
for i in range(p - x - 1, p):
if i == p - 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
if offset + N[i] >= q:
q -= offset
p = i + 1
print(' = b[{}][{}]'.format(p, q), end='')
break
offset += N[i]
print()
return p, b[p - 1]
Calling so38509640('abc', 9, 45) produces
N = [1, 1, 1, 3, 5, 9, 17, 31, 57]
b[9][45] = b[8][19] = b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Similarly, for the example in the question, so38509640('abc', 7, 5) produces the expected result:
N = [1, 1, 1, 3, 5, 9, 17]
b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Sorry I couldn't come up with a better function name :) This is simple enough code that it should work equally well in Py2 and 3, despite differences in the range function/class.
I would be very curious to see if there is a non-iterative solution for this problem. Perhaps there is a way of doing this using modular arithmetic or something...

Resources