Swapping maximum and minimum values in a list - python

Given a list (for instance, [1,1,2,1,2,2,3]) which is not sorted highest to lowest, and contains multiples of all numbers, I need to swap, in place, the maximums with the minimums, the second maxes with the second mins, etc. So, our example list would become [3,3,2,3,2,2,1].
Also, just to clarify, it's not just the max and min, but each layer of maxes and mins. So if the max was 4, 1's and 4's should switch as well as 2's and 3's.
I found this question on the topic: How to swap maximums with the minimums? (python)
but the code examples given seemed verbose, and assumed that there were no duplicates in the list. Is there really no better way to do this? It seems like a simple enough thing.

This is one way to do it, possible because Python is such an expressive language:
>>> a = [1,1,2,1,2,2,3]
>>> d = dict(zip(sorted(set(a)), sorted(set(a), reverse=True)))
>>> [d[x] for x in a]
[3, 3, 2, 3, 2, 2, 1]

Related

How do I permute an array so that as many possible integers will move to a place where a smaller integer used to stand?

I'm trying to understand the solution to an algorithm/logic problem. The problem statement is as follows:
You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it so that as many as possible integers will become on a place where a smaller integer used to stand. Help Vasya find the maximal number of such integers. For instance, if we are given an array [10,20,30,40], we can permute it so that it becomes [20,40,10,30]. Then on the first and the second positions the integers became larger (20>10, 40>20) and did not on the third and the fourth, so for this permutation, the number that Vasya wants to maximize equals 2. Help Vasya to permute integers in such a way that the number of positions in a new array, where integers are greater than in the original one, is maximal.
Input:
The first line contains a single integer 𝑛 (1≤𝑛≤105) — the length of the array.
The second line contains 𝑛 integers 𝑎1,𝑎2,…,𝑎𝑛 (1≤𝑎𝑖≤109) — the elements of the array.
Output
Print a single integer — the maximal number of the array's elements which after a permutation will stand on the position where a smaller element stood in the initial array.
Sample I/O:
I've looked at the solution but couldn't really understand the intuition behind it. I understand how it works, but I don't understand WHY it works. Here's the solution:
The answer is 𝑛 minus maximal number of equal elements.
Let the maximal number of equals be 𝑥. Let's prove that 𝑛−𝑥 is reachable. It's clear that for every permutation of the array the answer will be the same, so let's sort the array in non-decreasing order. Now we should just make a left shift on 𝑥. After it, the 𝑛−𝑥 right elements will move to a position of a smaller element.
Now let's prove that the answer is no more than 𝑛−𝑥. Let's consider some permutation. It's known that every permutation breaks into cycles. Let's look at two occurrences of the same number in the same cycle. Then there is at least one number between them which will move on a position of a non-smaller element. Even if it the same occurrence and even if the length of the cycle is 1, we can say that for every occurrence of this number there is at least one number that moves on a position of a non-smaller one. So if some number occurs 𝑥 times, there are at least 𝑥 bad positions and therefore no more than 𝑛−𝑥 good positions.
Please explain to me why this solution works. I've tried tons of dry-runs but couldn't figure out the logic behind it. To me, this is black magic.
Perhaps a visual example could help:
If your array is already sorted you will get something like this:
[1, 2, 3, 4, 5]
If you shift it to the right by one position, every number except the last one will be replaced by a larger number. So n-1 is the maximum number of replacements you can do because the largest number cannot be replaced by a smaller one.
[1, 2, 3, 4, 5]
| | | |
[1, 2, 3, 4, 5]
If the array is not sorted, the replacements occur at different positions but there is the same number of pairs.
If you have a number that repeats, there will be one less larger/smaller replacement. So we end up with n-2 such replacements (where 2 is the maximum repetition)
[1, 2, 3, 3, 4, 5]
| | | |
[1, 2, 3, 3, 4, 5]
This can be explained by the fact that, to implement the nth replacement, you have to be able to perform the (n-1)th replacement, each of which requires a smaller value. So you'll need a value that has 1 smaller, a value that has 2 smaller, ... a value that has n-1 smaller values. Each repeated value breaks this sequence so a list of 7 elements with a value that has 2 duplicates (i.e. the same value 3 times) is like a list of 5 elements and can have 4 replacements (7-3).
However, if you have two different elements that repeat, you only face the worst case of the two because you can perform replacement again between the extra elements:
[1, 2, 3, 3, 4, 5, 5, 5, 6]
| | | | | 5 replacements
[1, 2, 3, 3, 4, 5, 5, 5, 6]
[3, 5, 5]
| 1 replacements
[3, 5, 5]
For 9 elements with 3 max repeated = 6 replacements
9-3 = 6 = N - maxRepeat

Finding points in a 2d array

I've started coding recently and my preferred language is python. I've come across a problem I'm having trouble with.
The problem is finding the index in a 2d array where the number is either larger than the numbers to the left and right and smaller than the numbers above and below or vice versa.
I know a 2d array can be defined as list = [[1, 2], [3, 4], [5, 6]] but as for working out the algorithm to sort the problem is at the present time beyond me. Could someone please offer a solution?
min(enumerate(list[0]),key=lambda x:x[1]) will find the (index,value) pair with the smallest value from list[0] ((0,1) in this example). max(enumerate(list[0]),key=lambda x:x[1]) will find the largest.
Note (since you said you're new) this is the same as:
def first_index(L):
return l[1]
min(enumerate(list[0]),key=first_index)
new_list=[L[0] for L in list] will make a list containing the 0th element from each list ([1,3,5] in this example). You'll probably want to do this for each column using for index in range(len(list[0]):
Note (since you're new) this is the same as:
new_list=list()
for L in list:
new_list.append(L[0])

Where am I wrong?

Question
Write function mssl() (minimum sum sub-list) that takes as input a list of integers.It then computes and returns the sum of the maximum sum sub-list of the input list. The maximum sum sub-list is a sub-list (slice) of the input list whose sum of entries is largest. The empty sub-list is defined to have sum 0. For example, the maximum sum sub-list of the list [4, -2, -8, 5, -2, 7, 7, 2, -6, 5] is [5, -2, 7, 7, 2] and the sum of its entries is 19.
l = [4, -2, -8, 5, -2, 7, 7, 2, -6, 5]
mssl(l)
19
mssl([3,4,5])
12
mssl([-2,-3,-5])
0
In the last example, the maximum sum sub-list is the empty sub-list because all list items are
negative.
THIS IS MY SOLUTION
def mssl(lst):
pos,neg,TotalList=[],[],[]
for items in range(len(lst)):
if(lst[items]>0):
pos+=[lst[items]]
else:
neg+=[lst[items]]
TotalPos=sum(pos)
TotalNeg=sum(neg)
if(len(neg)>0):
for negatives in range(len(neg)):
TotalList=[TotalPos+neg[negatives]]
if(TotalList>TotalList[negatives-1]):
print(TotalList)
else:
TotalList=TotalPos
print(TotalList)
THIS IS NOT A HOMEWORK QUESTION I AM LEARNING PYTHON FOR FUN, PLEASE LET ME KNOW WHERE I AM WRONG
It looks like you're trying to learn programming, with python as your first language. This particular problem is a somewhat difficult one to start with. I would advise you to take a straightforward, brute-force approach at first. Evaluate the sums of all the subsequences, one after another, and keep track of which is largest. Once you have a function that will produce the correct answer, you can look for a better (faster, more elegant, whatever) solution.
As to your code, it really has nothing to do with the question. For example, TotalList is always a one-element list. The expression TotalList[negatives-1] doesn't make much sense; if there's only one element in the list, you can access it as TotalList[0]. The expression TotalList>TotalList[negatives-1] makes no sense at all; you don't want to compare a list to a number.
This is a well-known problem, and a simple, fast solution is not at all easy to come up with, so don't be discouraged if you don't find it. Once you get a straightforward solution, you can think about an elegant one. This problem can be solved in one line of python, using list comprehensions. Trying to do that will lead to improvement in your python style. For example, instead of writing
for items in range(len(lst)):
if(lst[items]>0):
pos+=[lst[items]]
else:
neg+=[lst[items]]
you can, and should write
pos = [x for x in lst if x > 0]
neg = [x for x in lst if x < 0]
Good luck learning python.

Sorting Function. Explanantion

def my_sort(array):
length_of_array = range(1, len(array))
for i in length_of_array:
value = array[i]
last_value = array[i-1]
if value<last_value:
array[i]=last_value
array[i-1]=value
my_sort(array)
return array
I know what the function does in general. Its a sorting alogarithm.... But i dont know how what each individual part/section does.
Well, I have to say that the best way to understand this is to experiment with it, learn what it is using, and, basically, learn Python. :)
However, I'll go through the lines one-by-one to help:
Define a function named my_sort that accepts one argument named array. The rest of the lines are contained in this function.
Create a range of numbers using range that spans from 1 inclusive to the length of array non-inclusive. Then, assign this range to the variable length_of_array.
Start a for-loop that iterates through the range defined in the preceding line. Furthermore, assign each number returned to the variable i. This for-loop encloses lines 4 through 9.
Create a variable value that is equal to the item returned by indexing array at position i.
Create a variable last_value that is equal to the item returned by indexing array at position i-1.
Test if value is less than last_value. If so, run lines 7 through 9.
Make the i index of array equal last_value.
Make the i-1 index of array equal value.
Rerun my_sort recursively, passing in the argument array.
Return array for this iteration of the recursive function.
When array is finally sorted, the recursion will end and you will be left with array all nice and sorted.
I hope this shed some light on the subject!
I'll see what I can do for you. The code, for reference:
def my_sort(array):
length_of_array = range(1, len(array))
for i in length_of_array:
value = array[i]
last_value = array[i-1]
if value<last_value:
array[i]=last_value
array[i-1]=value
my_sort(array)
return array
def my_sort(array):
A function that takes an array as an argument.
length_of_array = range(1, len(array))
We set the variable length_of_array to a range of numbers that we can iterate over, based on the number of items in array. I assume you know what range does, but if you don't, in short you can iterate over it in the same way you'd iterate over a list. (You could also use xrange() here.)
for i in length_of_array:
value = array[i]
last_value = array[-1]
What we're doing is using the range to indirectly traverse the array because there's the same total of items in each. If we look closely, though, value uses the i as its index, which starts off at 1, so value is actually array[1], and last_value is array[1-1] or array[0].
if value<last_value:
array[i]=last_value
array[i-1]=value
So now we're comparing the values. Let's say we passed in [3, 1, 3, 2, 6, 4]. We're at the first iteration of the loop, so we're essentially saying, if array[1], which is 1, is less than array[0], which is 3, swap them. Of course 1 is less than 3, so swap them we do. But since the code can only compare each item to the previous item, there's no guarantee that array will be properly sorted from lowest to highest. Each iteration could unswap a properly swapped item if the item following it is larger (e.g. [2,5,6,4] will remain the same on the first two iterations -- they will be skipped over by the if test -- but when it hits the third, 6 will swap with 4, which is still wrong). In fact, if we were to finish this out without the call to my_sort(array) directly below it, our original array would evaluate to [1, 3, 2, 3, 4, 6]. Not quite right.
my_sort(array)
So we call my_sort() recursively. What we're basically saying is, if on the first iteration something is wrong, correct it, then pass the new array back to my_sort(). This sounds weird at first, but it works. If the if test was never satisfied at all, that would mean each item in our original list was smaller than the next, which is another way (the computer's way, really) of saying it was sorted in ascending order to begin with. That's the key. So if any list item is smaller than the preceding item, we jerk it one index left. But we don't really know if that's correct -- maybe it needs to go further still. So we have to go back to the beginning and (i.e., call my_sort() again on our newly-minted list), and recheck to see if we should pull it left again. If we can't, the if test fails (each item is smaller than the next) until it hits the next error. On each iteration, this teases the same smaller number leftward by one index until it's in its correct position. This sounds more confusing than it is, so let's just look at the output for each iteration:
[3, 1, 3, 2, 6, 4]
[1, 3, 3, 2, 6, 4]
[1, 3, 2, 3, 6, 4]
[1, 2, 3, 3, 6, 4]
[1, 2, 3, 3, 4, 6]
Are you seeing what's going on? How about if we only look at what's changing on each iteration:
[3, 1, ... # Wrong; swap. Further work ceases; recur (return to beginning with a fresh call to my_sort()).
[1, 3, 3, 2, ... # Wrong; swap. Further work ceases; recur
[1, 3, 2, ... # Wrong; swap. Further work ceases; recur
[1, 2, 3, 3, 6, 4 # Wrong; swap. Further work ceases; recur
[1, 2, 3, 3, 4, 6] # All numbers all smaller than following number; correct.
This allows the function to call itself as many times as it needs to pull a number from the back to the front. Again, each time it's called, it focuses on the first wrong instance, pulling it one left until it puts it in its proper position. Hope that helps! Let me know if you're still having trouble.

average of the list in Python

I have a problem: i need to find an average of the list using this scheme:
First of all, we find an average of two elements, three elements..... len(list) elements and form a new list using averages. The use .pop() and find all averages again. Function should stop when len(list) == 2. Recursion should be used.
Example:
list: [-1, 4, 8, 1]
1 step:
find an average of [-1, 4], [-1, 4, 8], [-1, 4, 8, 1]
Then we form a new list: [1.5, 3.66..., 3] (averages)
Then find averages of new list: [1.5, 3.66...], [1.5, 3.66..., 3]
Then we form a new list: [2.5833.., 7.222...] (averages)
When len(list) == 2, find an average of this two elements.
Answer is 2.652777.
What should i write:
jada = []
while True:
print 'Lst elements:'
a = input()
if (a == ''):
break
jada.append(a)
print 'Lst is:' + str(Jada)
def keskmine(Jada):
for i in range(len(Jada) - 1):
...
jada.pop()
return keskmine(Jada)
Actually, this is a part of a homework, but i don't know how to solve it.
Accept the list as the function argument. If the list has one item, return that. Create two iterators from the list. Pop one item off one of the lists, zip them together, then find the averages of the zip results. Recurse.
In short, you're finding the "running average" from a list of numbers.
Using recursion would be helpful here. Return the only element when "len(lst) == 1" otherwise, compute the running average and recurse.
There are two parts in this assignment. First, you need to transform lists like [-1, 4, 8, 1] to lists like [1.5, 3.66, 3] (find the running averages). Second, you need to repeat this process with the result of the running averages until your list's length is 2 (or 1).
You can tackle the first problem (find the running averages) independently from the second. Finding the running average is simple, you first keep track of the running sum (e.g. if the list is [-1, 4, 8, 1] the running sum is [-1, 3, 11, 12]) and divide each elements by their respective running index (i.e. just [1, 2, 3, 4]), to get [-1/1, 3/2, 11/3, 12/4] = [-1, 1.5, 3.66, 3]. Then you can discard the first element to get [1.5, 3.66, 3].
The second problem can be easily solved using recursion. Recursion is just another form of looping, all recursive code can be transformed to a regular for/while-loops code and all looping code can be transformed to recursive code. However, some problems have a tendency towards a more "natural" solution in either recursion or looping. In my opinion, the second problem (repeating the process of taking running averages) is more naturally solved using recursion. Let's assume you have solved the first problem (of finding the running average) and we have a function runavg(lst) to solve the first problem. We want to write a function which repeatedly find the running average of lst, or return the average when the lst's length is 2.
First I'll give you an explanation, and then some pseudo code, which you'll have to rewrite in Python. The main idea is to have one function that calls itself passing a lesser problem with each iteration. In this case you would like to decrease the number of items by 1.
You can either make a new list with every call, or reuse the same one if you'd like. Before passing on the list to the next iteration, you will need to calculate the averages thus creating a shorter list.
The idea is that you sum the numbers in a parameter and divide by the number of items you've added so far into the appropriate index in the list. Once you are done, you can pop the last item out.
The code should look something like this: (indexes in sample are zero based)
average(list[])
if(list.length == 0) // Check input and handle errors
exit
if(list.length == 1) // Recursion should stop
return list[0] // The one item is it's own average!
// calculate the averages into the list in indices 0 to length - 2
list.pop() // remove the last value
return average(list) // the recursion happens here
This is also an opportunity to use python 3.x itertools.accumulate:
From docs:
>>> list(accumulate(8, 2, 50))
[8, 10, 60]
Then, you only need to divide each item by its index increased by 1, eliminate the first element and repeat until finished
For example, this works for any list of any length, doing most of the above-indicated steps inside a list comprehension:
>>> from itertools import accumulate
>>> a = [-1, 4, 8, 1]
>>> while len(a) > 1:
a = [item / (index + 1) for (index, item) in enumerate(accumulate(a)) if index > 0]
>>> print(a)
[2.6527777777777777]

Categories

Resources