Here is a list a=[1,1,1,2,4,2,4,32,1,4,35,23,24,23]
I do this in python:
unique_number=list(set(a))
ans=map(lambda x:a.index(x),unique_number)
output:
<map at 0x2b98b307828>
I want to know what's wrong with my code and find an more efficient way to achieve this.
This code would work as you expected in Python 2. In Python 3, map returns an iterator. You could, e.g., convert it to a list:
>>> ans=map(lambda x:a.index(x),unique_number)
>>> list(ans)
[7, 0, 3, 10, 4, 11, 12]
You can avoid keep re-indexing and building a set first - simply build a dict iterating over a backwards as the dictionary will only keep the last value for a key (in this case - the earliest appearing index), eg:
a=[1,1,1,2,4,2,4,32,1,4,35,23,24,23]
first_index = {v:len(a) - k for k,v in enumerate(reversed(a), 1)}
# {1: 0, 2: 3, 4: 4, 23: 11, 24: 12, 32: 7, 35: 10}
This way you're only scanning the sequence once.
Try this:
for value in map(lambda x:a.index(x),unique_number):
print(value)
or append this:
for var in ans:
print(var)
Related
I have the following frozenset:
f_set = [frozenset({8, 14, 15, 18}), frozenset({1, 2, 3, 7, 8}), frozenset({0, 4, 5})]
I need to convert f_set into a dictionary as the following
For the first set, I need the dictionary to have a value of 0.
For the second set, I need the dictionary to have a value of 1.
For the third set, I need the dictionary to have a value of 2.
Now, in case some keys are existed in multiple set, assign a new values to them. In this case 8 existed in both set 1 and set 2, so assign a value of 3.
dict1 = {8:3, 14:0, 15:0, 18:0, 1:1, 2:1, 3:1, 7:1, 0:2, 4:2, 5:2}
Note: my actual f_set contains more than three sets, so I'd like to avoid doing that manually.
You can use dict comprehension with enumerate:
f_set = [frozenset({8, 14, 15, 18}), frozenset({1, 2, 3, 7, 8}), frozenset({0, 4, 5})]
dict1 = {x: i for i, s in enumerate(f_set) for x in s}
print(dict1)
# {8: 1, 18: 0, 14: 0, 15: 0, 1: 1, 2: 1, 3: 1, 7: 1, 0: 2, 4: 2, 5: 2}
Note that, if the sets are not mutually disjoint, some keys will be discarded, since a dict cannot have duplicate keys.
You can simply loop over the frozensets to set each of them in an output dictionary:
output = dict()
for i in range(len(f_set)):
for s in f_set[i]:
output[s] = i
Note although the order may be different from what you have, order shouldn't matter in the dictionary.
I'm new to programming and I don't understand what happens. Can someone explain what's going on?
>>> primes = {1: 2, 2: 3, 4: 7, 7: 17}
>>> primes[4]
7
>>> primes[primes[4]]
17
Why does primes[primes[4]] result in 17?
Given the dictionary primes = {1: 2, 2: 3, 4: 7, 7: 17}, primes[4] results in 7.
When evaluating the expression primes[primes[4]], Python has to evaluate primes[4] first, which, as we have seen, is 7.
So primes[primes[4]] is equivalent to primes[7].
I hope you can see that, given the above dictionary, primes[7] results in 17.
To start, the primes variable is a Python dictionary. So let's start by looking at an example:
A dictionary in Python defines key-value pairs. For example, say we have an "ages" dictionary:
ages = {
"James": 20,
"Mike": 13
}
With this data structure, if I wanted to get James' age, I'd say ages['james'] and this value would be an integer, 20.
Well, the same applies to your structure here, except instead of strings for the keys, you have integers. So let's take a look:
primes = {
1: 2,
2: 3,
4: 7,
7: 17
}
If we want to get the 17, we'd go ahead and say primes[7], as the integer 7 is referring to the number 17.
I realize that title may be confusing, so allow me to explain.
I take input from a list that looks like L = [21.123, 22.123, 23.123, 21.123]
I remove the decimals, and sort the list high to low. I also change it to a dictionary with occurrences, which looks like
newlist = {23: 1, 22: 1, 21: 2}
What I need to do is to make a list of keys and values, which I can do. This gives me two lists, of [23, 22, 21] and [1, 1, 2] one for values and one for occurrences. I need to turn my occurrence list into the number of occurrences that are the same as, or lower than it's corresponding key.
I would like my list to look like [23, 22, 21] (which is easy to do) and [4, 3, 2] because 4 of the times are 23 seconds or less, 3 of the times are 22 seconds or less, and 2 of the times are 21 seconds or less.
I'm pretty sure I need a for loop to iterate through every frequency value, and change that value to be the total number of times entered into the list, and subtract any value more than it. I'm not sure how to go about this, so any help would be greatly appreciated.
You want a dictionary where, for each item in your data, the key is the rounded value (int(item)) and the value is the number of of items that are smaller than or equal to this rounded value.
A dictionary comprehension (combined with a list comprehension) can do this:
data = [21.123, 22.123, 23.123, 21.123]
aggregate = {
item: len([n for n in data if int(n) <= item])
for item in set(map(int, data))
}
print(aggregate) # -> {21: 2, 22: 3, 23: 4}
which is the single-statement form of writing such a loop:
aggregate = {}
for item in set(map(int, data)):
aggregate[item] = len([n for n in data if int(n) <= item])
}
Using set() makes the list unique. This way the loop only runs as often as necessary.
Here's a functional solution. The marginally tricky part is the backwards cumulative sum, which is possible feeding a reversed tuple to itertools.accumulate and then reversing the result.
from collections import Counter
from itertools import accumulate
from operator import itemgetter
L = [21.123, 22.123, 23.123, 21.123]
c = Counter(map(int, L)) # Counter({21: 2, 22: 1, 23: 1})
counter = sorted(c.items(), reverse=True) # [(23, 1), (22, 1), (21, 2)]
keys, counts = zip(*counter) # ((23, 22, 21), (1, 1, 2))
cumsum = list(accumulate(counts[::-1]))[::-1] # [4, 3, 2]
Your desired result is stored in keys and cumsum:
print(keys)
(23, 22, 21)
print(cumsum)
[4, 3, 2]
Assuming you get the counts correctly from [21.123, 22.123, 23.123, 21.123], a simple nested loop with a running sum can do the rest:
from collections import Counter
newlist = {23: 1, 22: 1, 21: 2}
counts = Counter()
for k in newlist:
for v in newlist:
if v <= k:
counts[k] += newlist[v]
print(counts)
# Counter({23: 4, 22: 3, 21: 2})
You could also use itertools.product() to condense the double loops into one:
from itertools import product
from collections import Counter
newlist = {23: 1, 22: 1, 21: 2}
counts = Counter()
for k, v in product(newlist, repeat=2):
if v <= k:
counts[k] += newlist[v]
print(counts)
# Counter({23: 4, 22: 3, 21: 2})
The above stores the counts in a collections.Counter(), you can get [4, 3, 2] by calling list(counts.values()).
I found my own solution which seems relatively simple. Code looks like
counter = 0
print(valuelist)
for i in valuelist:
print(int(solves - counter))
counter = counter + i
redonevalues.append(solves - counter + 1)
It takes my values, goes to the first one, adds the occurrences to counter, subtracts counter from solves, and adds 1 to even it out
I need to build up a counting function starting from a dictionary. The dictionary is a classical Bag_of_Words and looks like as follows:
D={'the':5, 'pow':2, 'poo':2, 'row':2, 'bub':1, 'bob':1}
I need the function that for a given integer returns the number of words with at least that number of occurrences. In the example F(2)=4, all words but 'bub' and 'bob'.
First of all I build up the inverse dictionary of D:
ID={5:1, 2:3, 1:2}
I think I'm fine with that. Then here is the code:
values=list(ID.keys())
values.sort(reverse=True)
Lk=[]
Nw=0
for val in values:
Nw=Nw+ID[val]
Lk.append([Nw, val])
The code works fine but I do not like it. The point is that I would prefer to use a list comprehension to build up Lk; also I really ate the Nw variable I have used. It does not seems pythonic at all
you can create a sorted array of your word counts then find the insertion point with np.searchsorted to get how many items are to either side of it... np.searchsorted is very efficient and fast. If your dictionary doesn't change often this call is basically free compared to other methods
import numpy as np
def F(n, D):
#creating the array each time would be slow if it doesn't change move this
#outside the function
arr = np.array(D.values())
arr.sort()
L = len(arr)
return L - np.searchsorted(arr, n) #this line does all the work...
what's going on....
first we take just the word counts (and convert to a sorted array)...
D = {"I'm": 12, "pretty": 3, "sure":12, "the": 45, "Donald": 12, "is": 3, "on": 90, "crack": 11}
vals = np.arrau(D.values())
#vals = array([90, 12, 12, 3, 11, 12, 45, 3])
vals.sort()
#vals = array([ 3, 3, 11, 12, 12, 12, 45, 90])
then if we want to know how many values are greater than or equal to n, we simply find the length of the list beyond the first number greater than or equal to n. We do this by determining the leftmost index where n would be inserted (insertion sort) and subtracting that from the total number of positions (len)
# how many are >= 10?
# insertion point for value of 10..
#
# | index: 2
# v
# array([ 3, 3, 11, 12, 12, 12, 45, 90])
#find how many elements there are
#len(arr) = 8
#subtract.. 2-8 = 6 elements that are >= 10
A fun little trick for counting things: True has a numerical value of 1 and False has a numerical value of 0. SO we can do things like
sum(v >= k for v in D.values())
where k is the value you're comparing against.
collections.Counter() is ideal choice for this. Use them on dict.values() list. Also, you need not to install them explicitly like numpy. Sample example:
>>> from collections import Counter
>>> D = {'the': 5, 'pow': 2, 'poo': 2, 'row': 2, 'bub': 1, 'bob': 1}
>>> c = Counter(D.values())
>>> c
{2: 3, 1: 2, 5: 1}
I've got a system in which I often (but not constantly) have to find the next item in a tuple. I'm currently doing this like so:
mytuple = (2,6,4,8,7,9,14,3)
currentelement = 4
def f(mytuple, currentelement):
return mytuple[mytuple.index(currentelement) + 1]
nextelement = f(mytuple, currentelement)
All elements are unique and I am not stuck with the tuple, I can make it something else earlier in the program if needed.
Since I need to do this a lot, I was wondering whether there is any more efficient way to do this?
Use a dict here, dicts provide O(1) lookup compared to list.index which is an O(N) operation.
And this will work for strings as well.
>>> lis = (2,6,4,8,7,9,14,3)
>>> dic = dict(zip(lis, lis[1:]))
>>> dic[4]
8
>>> dic[7]
9
>>> dic.get(100, 'not found') #dict.get can handle key errors
'not found'
A memory efficient version to create the above dict:
>>> from itertools import izip
>>> lis = (2,6,4,8,7,9,14,3)
>>> it1 = iter(lis)
>>> it2 = iter(lis)
>>> next(it2)
2
>>> dict(izip(it1,it2))
{2: 6, 4: 8, 6: 4, 7: 9, 8: 7, 9: 14, 14: 3}
You might wish to build an index using a dictionary:
# The list
>>> lis = (2,6,4,8,7,9,14,3)
# build the index
>>> index = dict(zip(lis, range(len(lis))))
>>> index
{2: 0, 3: 7, 4: 2, 6: 1, 7: 4, 8: 3, 9: 5, 14: 6}
# Retrieve position by using the index
>>> index[6]
1
>>> lis[index[6]+1]
4
If your list change over time, you will have to rebuild the index. For a more memory efficient solution, you might prefer using izip instead of `zip̀ as suggested in an other answer.