Python Intelligent rounding of numbers - python

I have some weird numbers such as 19 or 23. These two will need to be separated into 5 lists, such that the sum of the 5 lists will be 19. In other words, 3.8 in each list as 19/5 = 3.8. However the issue is that I can't have decimals, I want rounded numbers. Is there any way that it would round the numbers accordingly, placing 4, 4, 3, 4, 4 into the lists rather than 3.8 five times?
Even more, some aren't separated into 5 different numbers. Some might be something like 77/12, thus being separated into 12 diff. lists with either the number 6 or 7 in each, that ends up adding to 77.
Any idea how I could approach this problem?
Thanks!

def split(number, length):
div, mod = divmod(number, length)
return [div+1]*mod + [div]*(length-mod)
>>> split(19, 5)
[4, 4, 4, 4, 3]
>>> split(23, 4)
[6, 6, 6, 5]
Original version:
def split(number, length):
result = [number//length]*length
for i in range(number%length):
result[i] += 1
return result

here you go.
def roundto(number,items):
start = [1 for i in xrange(items)]
reached = False
while not reached:
for i in xrange(len(start)):
start[i] += 1
if sum(start) == number:
return start
print roundto(19,5)
>>>
[4, 4, 4, 4, 3]

Related

python homework interleaving list

The problem statement is:
Design and implement an algorithm that displays the elements of a list
by interleaving an element from the beginning and an element from the
end.
For example, input:
1 2 3 4 5 6 7 8
Output :
1 8 2 7 3 6 4 5
This is what I tried, but I don't know what happen with elements 7 and 8:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(len(lista)):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 7, 2, 8, 3, 6, 4, 5]
The only error in you code, is that range(len(lista)) starts from 0, not from 1. By starting from zero, in the first iteration 2*i-1 will be 2*0-1 = -1, and hence lista.insert(-1,lista.pop()), which means inserting at the very end of the list (that is what index -1 means in python).
To fix your code, you just need to start the range from 1. Actually, you are iterating too much, you can have your range just from 1 to the half of your list, like this:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(1, len(lista)//2):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 8, 2, 7, 3, 6, 4, 5]
When you become more familiarized with the language, you will see that this can be accomplished much more easily.
For example, you can use the python slice syntax to achieve your goal. You slice from beginning to half , and from end to half (step of -1), then zip then together and flat.
[i for z in zip(lista[:4],lista[:-5:-1]) for i in z]
# [1, 8, 2, 7, 3, 6, 4, 5]
Another option:
import math
lista = [1, 2, 3, 4, 5, 6, 7, 8]
ans = []
for i in range(math.floor(len(lista)/2)):
ans.append(lista[i])
ans.append(lista[-i-1])
if (len(lista) % 2) != 0:
ans.append(lista(math.ceil(len(lista)/2)))
print(ans)
Technically speaking, I'd say it's two off-by-one errors (or one off-by-one error, but from -1 to +1, you'll see what I mean in the second paragraph). The first one is that you're subtracting 1 when you shouldn't. In the case when i = 0 (remember that range(n) goes from 0 to n-1), the insert position is being evaluated as 2*0-1 = (2*0)-1 = 0-1= -1 (for insert() method, that's the last position of the original list, pushing what was there forward, so it'll be the penultimate position of the NEW list).
But, when you remove the -1, the output becomes 8 1 7 2 6 3 5 4, which is close to what you want, but not quite right. What's missing is that the elements inserted should be at positions 1, 3, 5, 7, and not 0, 2, 4, 6. So, you'll actually need to add 1.
So, the shortest change to fix your code is to change lista.insert(2*i-1,lista.pop()) to lista.insert(2*i+1,lista.pop()).
Notice: if you put a print inside for, you'll realize that, after changing half the elements, the output is already right. That's because when len(lista) is 8, and you do lista.insert(x, lista.pop()) where x is bigger than 8, basically you're removing the last element (pop) and adding it at the end, so, nothing changes. Hence, you could also change range(len(lista)) to range(len(lista)//2). Test if it'll work when len(lista) is odd

How can I express a string range that is backwards into a list?

For example, let's say that I have a range of "10-1," how can I express this to say [1 2 3 4 5 6 7 8 9 10]?
You can use split to read the start and end, use int to convert them into integers, and then use range to return a desired list.
def range_to_list(s):
end, start = map(int, s.split('-'))
return list(range(start, end + 1))
print(range_to_list('10-1')) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Depending on your goal, list might not be necessary.

How could I write a function to find fractional ranking of a list of numbers?

I'm trying to write a code in Python to create a fractional ranking list for a given one.
The fraction ranking is basically the following:
We have a list of numbers x = [4,4,10,4,10,2,4,1,1,2]
First, we need to sort the list in ascending order. I will use insertion sort for it, I already coded this part.
Now we have the sorted list x = [1, 1, 2, 2, 4, 4, 4, 4, 10, 10]. The list has 10 elements and we need to compare it with a list of the first 10 natural numbers n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
For each element in x we assign a value. Notice the number 1 appears in positions 1 and 2. So, the number 1 receives the rank (1 + 2) / 2 = 1.5.
The number 2 appears in positions 3 and 4, so it receives the rank (3 + 4) / 2 = 3.5.
The number 4 appears in positions 5, 6, 7 and 8, so it receives the rank (5 + 6 + 7 + 8) / 4 = 6.5
The number 10 appears in positions 9 and 10, so it receives the rank (9 + 10) / 2 = 9.5
In the end of this process we need to have a new list of ranks r = [1.5, 1.5, 3.5, 3.5, 6.5, 6.5, 6.5, 6.5, 9.5, 9.5]
I don't want an entire solution, I want some tips to guide me while writing down the code.
I'm trying to use the for function to make a new list using the elements in the original one, but my first attempt failed so bad. I tried to get at least the first elements right, but it didn't work as expected:
# Suppose the list is already sorted.
def ranking(x):
l = len(x)
for ele in range(1, l):
t = x[ele-1]
m = x.count(t)
i = 0
sum = 0
while i < m: # my intention was to get right at least the rank of the first item of the list
sum = sum + 1
i = i + 1
x[ele] = sum/t
return x
Any ideais about how could I solve this problem?
Ok, first, for your for loop there you can more easily loop through each element in the list by just saying for i in x:. At least for me, that would make it a little easier to read. Then, to get the rank, maybe loop through again with a nested for loop and check if it equals whatever element you're currently on. I don't know if that makes sense; I didn't want to provide too many details because you said you didn't want the full solution (definitely reply if you want me to explain better).
Here is an idea:
You can use x.count(1) to see how many number 1s you have in list, x.count(2) for number 2 etc.
Also, never use sum as a variable name since it is an inbuilt function.
Maybe use 2 for loops. First one will go through elements in list x, second one will also go through elements in list x, and if it finds the same element, appends it to new_list.
You can then use something like sum(new_list) and clear list after each iteration.
You don't even need to loop through list n if you use indexing while looping through x
for i, y in enumerate(x) so you could use n[i] to read the value
If you want the code I'll post it in the comment
#VictorPaesPlinio- would you try this sample code for the problem: (it's a partial solution, did the data aggregation work, and leave the last part put the output for your own exercise).
from collections import defaultdict
x = [4, 4, 10, 4, 10, 2, 4, 1, 1, 2]
x.sort()
print(x)
lst = list(range(1, len(x)+1))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ranking = defaultdict(list)
for idx, num in enumerate(x, 1):
print(idx, num)
ranking[num].append(idx)
print(ranking)
'''defaultdict(<class 'list'>, {1: [1, 2], 2: [3, 4],
4: [5, 6, 7, 8], 10: [9, 10]})
'''
r = []
# r = [1.5, 1.5, 3.5, 3.5, 6.5, 6.5, 6.5, 6.5, 9.5, 9.5]
# 1 1 2 2 4 4 4 4 10 10
for key, values in ranking.items():
# key is the number, values in the list()
print(key, values, sum(values))
Outputs:
1 [1, 2] 3
2 [3, 4] 7
4 [5, 6, 7, 8] 26
10 [9, 10] 19 # then you can do the final outputs part...

How can i sum every nth number from list recursively?

I want to add every nth number from list recursively, but NOT the first number, so lets say I have a list [1, 2, 3, 4, 5, 6] and I want to add every 2nd number, so that would mean I need to add 2 + 4 + 6 but if I want to add every 3rd number, then it should add 3 + 6.
So right now I have this much, I want to add every 2nd number so that means I want to add 2, 4 and 6, but I can't seem to figure out why it doesn't work, what should I do differently?
def getsum(numbers):
if len(piece)==0:
return 0
else:
return getsum(numbers[2:]) + numbers[0]
print getSum([1, 2, 3, 4, 5, 6])
You can pick out the nth number, then recursively slice off everything after that when you call the function again
def get_sum(numbers, n):
if len(numbers) < n:
return 0
return numbers[n-1] + get_sum(numbers[n:], n)
For example with n = 2 and n = 3 respectively
>>> get_sum([1, 2, 3, 4, 5, 6], 2) # 2 + 4 + 6
12
>>> get_sum([1, 2, 3, 4, 5, 6], 3) # 3 + 6
9

Limiting number of input values in an array/list in Python

I'm obtaining input values in a list using the following statement:
ar = map(int, raw_input().split())
However, I would want to limit the number of inputs a user can give at a time. For instance, if the limit is specified by a number n, the array should only capture the first n values entered during the program.
e.g: if n = 6,
Input:
1 2 3 4 5 6 7 8 9 10
On performing 'print ar', it should display the following without any error messages:
[1, 2, 3, 4, 5, 6]
If you want to ignore the rest of the input, then you can use slicing to take only the first n input. Example -
n = 6
ar = map(int, raw_input().split(None, n)[:n])
We are also using the maxsplit option for str.split so that it only splits 6 times , and then takes the first 6 elements and converts them to int.
This is for a bit more performance. We can also do the simple - ar = map(int, raw_input().split())[:n] but it would be less performant than the above solution.
Demo -
>>> n = 6
>>> ar = map(int, raw_input().split(None, n)[:n])
1 2 3 4 5 6 7 8 9 0 1 2 3 4 6
>>> print ar
[1, 2, 3, 4, 5, 6]
How about indexing ar to just the 6th element? Technically, it's to the 7th element, as newarray will slice up to, but not including nth element
ar = map(int, raw_input().split())
print ar
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
newarray=ar[0:6]
print newarray
#[1, 2, 3, 4, 5, 6]
This should allow for unlimited input
I was looking for a solution to the same question.
I figured out what I can do below is my solution.
bookid = []
M = int(input())
S = input().split()
for i in range(M):
books.append(S[i])
print(booksid)
But I think it's definitely not the most effective way to do it but easy.

Categories