0

I have a list of integers ordered from maximum to minimum, like this: [2345,67,24,24,11,11,6,6,6,6,6,3,3,3,3,3,1,1,1,1,1,1]

I just simply want to calculate the portion of each value in this list, like 5% is '1', 4% is '3' ,1% is 2345 and print out this result

What's an easy way to do this?

mtrw
35.3k7 gold badges66 silver badges73 bronze badges
asked Dec 6, 2011 at 12:04
4
  • 2
    Can you clarify a bit what you mean by "the portion of each value"? Commented Dec 6, 2011 at 12:10
  • 1
    Yes. Please clarify. My answer assumed that you meant the fraction of elements that are 1, 3 etc. expressed as a percentage. Commented Dec 6, 2011 at 12:13
  • From the phrasing of the question I would have assumed it was a percentile question, but the numbers are way off from that assumption. Commented Dec 6, 2011 at 13:05
  • What did you try? Please post the code you started with. Commented Dec 6, 2011 at 13:19

4 Answers 4

3

One way. I'm sure there will be better ways to do it.

 import collections
 d = collections.defaultdict(float)
 ip = [2345,67,24,24,11,11,6,6,6,6,6,3,3,3,3,3,1,1,1,1,1,1]
 length = len(ip)
 for i in ip:
 d[i] += 1
 for i in d:
 print "%5d : %.2f%%" % (i, (d[i]/length) * 100)
answered Dec 6, 2011 at 12:11
Sign up to request clarification or add additional context in comments.

5 Comments

This solution also doesn't match the expected output from the OP... but its nice! :)
It is difficult to match the expected output from the OP, given that the percentages he gives do not correspond to the example.
@rodrigo - You can't exclude that you misunderstood what the OP wants, and his figures correspond - in fact - to the example... with the right computation applied.
@mac Maybe... but I'd bet that he simple gave approximate values to the percentages, because if he knew the actual values, he wouldn't need to ask in the first place!
The question title is "simple calculation in python", not "how to format percentage output". I'm pretty sure the important part is the algorithm to calculate percentage composition of an ordered list.
2

This solution takes advantage of the fact that your elements are already ordered, and only makes a single pass through your original list (and a constant number of passes through the remaining data structures.

>>> from itertools import groupby
>>> x = [2345,67,24,24,11,11,6,6,6,6,6,3,3,3,3,3,1,1,1,1,1,1]
>>> grouped_x = [(k, sum(1 for i in g)) for k,g in groupby(x)]
>>> grouped_x
[(2345, 1), (67, 1), (24, 2), (11, 2), (6, 5), (3, 5), (1, 6)]

The groupby expression is borrowed from the first question I ever asked on SO, and basically just groups each contiguous block of the same value into a list of (value, instance generator) pairs. Then the outer list comprehension just converts the instance generators into their total length.

I think OP's figures were not accurate, but this seems to be something like what he was getting at. I took the ceiling function, but you could also round

>>> from math import ceil
>>> for k, v in grouped_x:
print int(ceil(100 * v / float(len(x)))),
print "% is", k
5 % is 2345
5 % is 67
10 % is 24
10 % is 11
23 % is 6
23 % is 3
28 % is 1
answered Dec 6, 2011 at 12:17

3 Comments

Another answer that does not match the expected output... yet nicely done! :)
I believe it matches now. However I don't think the format of the output was the most important thing about this question.
Neat. I love examples from itertools since it's one of the things I don't use enough.
0

Not a simple function, but a bit of list comprehension:

x = [2345,67,24,24,11,11,6,6,6,6,6,3,3,3,3,3,1,1,1,1,1,1]
print [(i,x.count(i) * 100 / len(x)) for i in set(x)]

Will print

[(1, 27), (67, 4), (6, 22), (2345, 4), (11, 9), (3, 22), (24, 9)]

That are pairs of element / percent.

answered Dec 6, 2011 at 12:08

2 Comments

...with the only problem none of your values are the one expected by the OP! :(
Details, details... There are more efficient algorithms, but I was looking for a one-liner. Being ordered, it is easy to solve in O(n).
0
from collections import Counter, OrderedDict
items_count = len(x)
percentage_tuples = map(lambda tup: (tup[0], 100 * float(tup[1]) / items_count),
 Counter(x).most_common())
percentage_dict = OrderedDict(percentage_tuples)

percentage_dict will be ordered by portion from high to lower.

to print it out:

for item in percentage_tuples:
 print("%d%% is '%s'" % (item[1], item[0]))
answered Dec 6, 2011 at 12:25

9 Comments

This is unreadable, and would send most users to the man pages for about 3 hours.
what line seems unreadable for you? there are 2 collections imported and only their methods are used. the map with lambda could be a little bit unreadable but after looking closely it is nice enough this code is for learning how to make things. i suggest to write a subclass of the Counter collection to do all calculations
I personally don't like the use of lambda and map. That line is longer than I'd prefer.
I do. I generally prefer using genexps to using map. Your use of the collections is elegant but I'd have written that line like this percentage_tuples = ((i[0], 100*float(i[1])/items_count) for i in Counter(x).most_common()). It would probably run faster and have better memory characteristics for large lists as well.
@NoufalIbrahim just one thing: maps are faster than comprehensions. test it yourself. but lambda could decrease performance here...;)
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.