Printing a histogram - python

I have a list of integer percentages which I need to print using the following pattern:
The index of a value, a tab (8 spaces), a '*' printed for each percentage point
also if the value for an index is 0, print 'less than 1 percent'
I have tried this code:
for b in new_tally:
if b > 0:
print new_tally[b], \t, '*' * b
else:
print 'Less than 1% of words had this length'
However I keep getting the error code: list index out of range.
I do not understand this at all, can someone point out what I have done wrong?

I think the code you wanted was:
>>> new_tally = [5, 7, 8, 6, 4, 2]
>>> for i, b in enumerate(new_tally, 1):
print i, ':', b, '*' * b
1 : 5 *****
2 : 7 *******
3 : 8 ********
4 : 6 ******
5 : 4 ****
6 : 2 **
The cause of the original traceback is that list members are looked up using square brackets instead of parentheses. new_tally(i) is a function call. new_tally[i] is an indexed lookup.

for key,val in new_tally.iteritems():
print('{k} {a}'.format(k=key,a='*'*int(val)))
or, if you want the histogram sorted in descending order of frequency:
import operator
for key,val in sorted(new_tally.items(),key=operator.itemgetter(1),reverse=True):
print('{k} {a}'.format(k=key,a='*'*int(val)))

first piece:
new_tally = [5, 7, 8, 6, 4, 2]
for b in new_tally:
print b
second piece:
new_tally = [5, 7, 8, 6, 4, 2]
for i in range(len(new_tally)):
print i, new_tally[i]
the above two do approximately the same thing. you are mixing up between visiting elements in sequence (first approach) versus accessing list elements by sequential index (second approach).

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 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 find the missing index using python pandas?

Example
Order_ID Name
1 Man
2 Boss
5 Don
7 Lil
9 Dom
10 Bob
Want to get an output as:
3 4 6 8 are the missing Order_ID
Try using a list comprehension with range:
print([i for i in range(1, 10) if i not in df['Order_ID']])
Output:
[3, 4, 6, 8]
Solution for generate missing values from index dynamically by maximum and minimum values:
print (np.setdiff1d(np.arange(df.index.min(), df.index.max() + 1), df.index).tolist())
[3, 4, 6, 8]
Convert the list to set and compute its difference with a set that contains integers ranging from min(lst) and max(lst).
lst=df["Order_ID"].to_list()
sorted(set(range(lst[0], lst[-1])) - set(lst))
> [3, 4, 6, 8]
Try this code;
Code Syntax
missData = list(filter(lambda x: x not in df['Order_ID'], range(1, df['Order_ID].max()+1)))
print(f"{missData} are the missing Order_ID")
Output
[3, 4, 6, 8] are the missing Order_ID
[Program finished]

How to slice list left and right, except middle part?

List:
x = [1, 6, 2, 7, 1, 6, 1]
len(x)
> 7
How would I split the list for the first 3 and last 3, thus value 7 is left alone using list slicing methods?
Output
x[0:2,4:6] #<-- This doesn't work
> [1, 6, 2, 1, 6, 1] #<-- Expected output
Meeting OP requeriment: "Is there a way to just keep it same brackets? x[...,...] similar to this one? " (not just using x[:3]+x[-3:]):
Use numpy.delete together with numpy.r_. Specify which first number of elements n1 and which last number of elements n2 you want to keep this way
import numpy as np
x = [1, 6, 2, 7, 1, 6, 1]
n1 = 3 # Keep first n1 elements
n2 = 3 # Keep last n2 elements
print(list(np.delete(x,(np.r_[n1:len(x)-n2])))) # [1 6 2 1 6 1]
You could do: x[0:3]+x[4:7] or x[:3]+x[-3:]. The second one gets the first 3 elements from the last and the first three elements from the right.

Convert a list of integers into a string with just one comma after x elements in Python

I am trying to convert for example this list
F=[6, 9, 4, 3, 6, 8]
into a string that looks like this:
"6 9 4, 3 6 8"
the comma after 3 elements in this case is from the length of tuples in another list.
Can't figure out how to do this, I'll be grateful for any help!
Thank you!
Edit: Okay so I am trying to write a progam that "multiplies" to matrizes by adding the elements and finding the minimum. (ci,j = min {ai,k + bk,j})
What I got so far is
A="4 3 , 1 7"
B="2 5 9, 8 6 1"
A1 = A.split(",")
B1 = B.split(",")
A2 = [tuple(int(y) for y in x.split()) for x in A1]
B2 = [tuple(int(y) for y in x.split()) for x in B1]
D = []
for k in range(len(A2)):
for j in range(len(B2[0])):
C = []
for i in range(len(A2[0])):
N = (A2[k][i] + B2[i][j])
C.append(N)
D.append((min(C)))
So what I wrote gives me the right numbers, but in a list. I tried some codes from the internet but it won't work. The given strings A and B can be matrices of nxm so that I can't just cut the list to two pieces and add them together.
Thank you!
You may also use list comprehension expression using zip as:
>>> my_list = [6, 9, 4, 3, 6, 8]
>>> n = 3
>>> ', '.join([' '.join(map(str, x)) for x in zip(*[my_list[i::n] for i in range(n)])])
'6 9 4, 3 6 8'
you can try below code:
F=[6, 9, 4, 3, 6, 8]
len_other_list = 3
F1 = F[:len_other_list]
F2 = F[len_other_list:]
reqd_string = ' '.join(map(str, F1))+', '+' '.join(map(str, F2))
One liner:
' '.join([str(i) if c != 3 else str(i)+', ' for c,i in enumerate(F,start=1)])
This will join all the elements by a space, adding a comma after the third element. Change the 3 in the line if you want to add the comma after a different element. The enumerate function is counting the number of elements in F with the index starting at 1.
The join string method will concatenate all elements of your list by ' ' (space).
Ok. 1 with regex also :)
import re
f = [6, 9, 4, 3, 6, 8]
a = re.sub(r"[\[\],]",r"", ''.join(str(f)))
print "\""+a[:5]+','+a[5:]+"\""
Output:
"6 9 4, 3 6 8"
I would suggest this:
F=[6, 9, 4, 3, 6, 8, 9, 10]
size = 3
s = ', '.join([' '.join(map(str, F[i:i+size])) for i in range(0, len(F), size)])

Categories