How to delete single value in a loop over dict? - python

I'd like to iterate over a dict with for loop in range of 3 and delete the first 3 values not keys from that dict.
d = {'dec': (8, 12, 7, 5, 3)}
for items, rang in zip(sorted(d.items(), reverse=True), range(3)):
.... ?

It is not clear what you are asking, but do you mean you want to remove the first three items in the tuple d['dec'] == (8, 12, 7, 5, 3) (i.e. 8, 12 and 7)? If so:
>>> d = {'dec': (8, 12, 7, 5, 3)}
>>> d['dec'] = d['dec'][3:]
>>> d
{'dec': (5, 3)}

In your example, your code pulls the whole d dict_items (('dec', (8,12,7,5,3))) and zips it up with the number zero (0) which is the first number from the range generator. It assigns that d dict_items to items, and the number zero to rang.
I don't think that's what you're trying to do, I think you're trying to sort the dictionaries by month, then remove the first three values from each month, is that right?
If so:
monthorder = ['jan','feb','mar','apr','may','jun','jul','aug','sept','oct','nov','dec']
d = {'dec': (8,12,7,5,3), ... } # I'm assuming this has more than one key
count = 0
for key, values in sorted(d.items(), key=lambda x: monthorder.index(x[0])):
d[key] = values[3:]
count += 1
if count == 3: break

Related

How do I sort with multiple conditions on python?

6 7 5 2 12
0 2 3 6 12
2 8 5 4 13
4 3 5 7 14
def getMinIndex(list, start, stop):
n=len(list)
min_index = start
for i in range(start,stop):
if list[i][4] > myList[min_index][4]:
min_index = i
return min_index
def swapElements(list,i,j):
temp = list[i]
list[i] = list[j]
list[j] = temp
With this code I manage to sort the last element on the list which is index 4 but I'm having problem to sort the 1st index as I want the results to be like this.
0 2 3 6 12
6 7 5 2 12
2 8 5 4 13
4 3 5 7 14
So if the last element is the same after sorting then I want to sort the 1st element. Can anyone help? Thanks :D
What you're looking for is a key function for items on your list. Let me illustrate with an example.
Sorting keys
Suppose you have a list of people. You want to sort them by height. You can't just sort them using sorted because they aren't comparable by default the way numbers are. You need to specify the key used for sorting. The key is the characteristic you want to sort on. In this case it could look like:
sorted(people, key=lambda person: person.height)
or, if you find the lambda notation confusing:
def get_height(person):
return person.height
sorted(people, key=get_height)
Sorting tuples
A tuple is a finite sequence of items: (2,3) (2-tuple or pair), (-3, 2, 1) (3-tuple) and so on. Tuples are sorted alphabetically automatically. You don't need to do anything.
What's special in your case is that you don't want to sort by the first element, then by the second, and so on. You want to sort by the fourth and then by the first.
This is where keys enter the scene.
Tying it all together
You need a key function that will turn (a, b, c, d, e) into (e, a) which means: sort by the fifth column first and then by the first one:
def sorting_key(item):
return (item[4], item[0])
Then you can just call:
sorted(items, key=sorting_key)
# or with a lambda
sorted(items, key=lambda item: (item[4], item[0]))
Getting the index corresponding to a minimum
I noticed that your function returns a minimum corresponding to the element. You can sort the whole thing and take the first element. Alternatively, you can use the built-in min function and provide it the sorting key.
The only thing you need to take into account is that min returns the corresponding value, not the index. You can work around this with:
min_index, min_value = min(enumerate(items), key=lambda (index, value): (value[4], value[0]))
enumerate pairs list items with their indexes so [a, b, c] becomes [(0, a), (1, b), (2, c)]. Then you sort these pairs as if the indexes weren't present: key accepts index as the first argument in a tuple but ignores it completely.
You can use operator.itemgetter and use it for a custom sorting key function which you can pass to one of the built-in sort functions:
> from operator import itemgetter
> lst = [
[2, 8, 5, 4, 13],
[6, 7, 5, 2, 12],
[4, 3, 5, 7, 14],
[0, 2, 3, 6, 12]
]
# use tuple of last and first elmnt as sorting key
> sorted(lst, key=itemgetter(-1, 0))
[
[0, 2, 3, 6, 12],
[6, 7, 5, 2, 12],
[2, 8, 5, 4, 13],
[4, 3, 5, 7, 14]
]

Inserting element Python

lst=[5,6,7,8,9]
v=10
for item in lst:
if item<v:
lst.insert(0,v)
print(lst)
i want to insert 10, at the index 0 if all the elements in the list are under 10, im not tryning to insert 10 each time
so it should look like this : [10,5,6,7,8,9]
You are inserting the same value of v at the beginning of the original list based on how many of the original values are less than v. In this case, preservation of insertion order is moot.
All inserted values are the same and are prepended to an original list that doesn't change.
So why not use something this
lst = [5, 6, 7, 8, 9]
v = 10
count = 0
for item in lst:
if item < v:
count += 1
new_lst = [v] * count + lst
print(new_lst)
Result
>>> [10, 10, 10, 10, 10, 5, 6, 7, 8, 9]
Edit: Updating answer based on further clarification
i want to insert 10, at the index 0 if all the elements in the
list are under 10, im not tryning to insert 10 each time
lst = [5, 6, 7, 8, 9]
v = 10
for item in lst[:]:
if item < v:
lst.insert(0, v)
break
print(lst)
Result
>>> [10, 5, 6, 7, 8, 9]
The updated code will insert v at index 0 only once if a single item is less than v. When the item < v condition is met the for loop ends without checking any of the remaining items. Otherwise, if None of the values are less than v, you will traverse the entirety of your list without making any changes.
Notice that I used the insert method here since this code will shift all of your lst items only once.

enumerate() for dictionary in Python

I know we use enumerate for iterating a list but I tried it on a dictionary and it didn't give an error.
CODE:
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, key in enumerate(enumm):
print(i, key)
OUTPUT:
0 0
1 1
2 2
3 4
4 5
5 6
6 7
Can someone please explain the output?
On top of the already provided answers there is a very nice pattern in Python that allows you to enumerate both keys and values of a dictionary.
The normal case you enumerate the keys of the dictionary:
example_dict = {1:'a', 2:'b', 3:'c', 4:'d'}
for i, k in enumerate(example_dict):
print(i, k)
Which outputs:
0 1
1 2
2 3
3 4
But if you want to enumerate through both keys and values this is the way:
for i, (k, v) in enumerate(example_dict.items()):
print(i, k, v)
Which outputs:
0 1 a
1 2 b
2 3 c
3 4 d
The first column of output is the index of each item in enumm and the second one is its keys. If you want to iterate your dictionary then use .items():
for k, v in enumm.items():
print(k, v)
And the output should look like:
0 1
1 2
2 3
4 4
5 5
6 6
7 7
Just thought I'd add, if you'd like to enumerate over the index, key, and values of a dictionary, your for loop should look like this:
for index, (key, value) in enumerate(your_dict.items()):
print(index, key, value)
dict1={'a':1, 'b':'banana'}
To list the dictionary in Python 2.x:
for k,v in dict1.iteritems():
print k,v
In Python 3.x use:
for k,v in dict1.items():
print(k,v)
# a 1
# b banana
Finally, as others have indicated, if you want a running index, you can have that too:
for i in enumerate(dict1.items()):
print(i)
# (0, ('a', 1))
# (1, ('b', 'banana'))
But this defeats the purpose of a dictionary (map, associative array) , which is an efficient data structure for telephone-book-style look-up. Dictionary ordering could be incidental to the implementation and should not be relied upon. If you need the order, use OrderedDict instead.
enumerate() when working on list actually gives the index and the value of the items inside the list.
For example:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i, j in enumerate(list):
print(i, j)
gives
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
where the first column denotes the index of the item and 2nd column denotes the items itself.
In a dictionary
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, j in enumerate(enumm):
print(i, j)
it gives the output
0 0
1 1
2 2
3 4
4 5
5 6
6 7
where the first column gives the index of the key:value pairs and the second column denotes the keys of the dictionary enumm.
So if you want the first column to be the keys and second columns as values, better try out dict.iteritems()(Python 2) or dict.items() (Python 3)
for i, j in enumm.items():
print(i, j)
output
0 1
1 2
2 3
4 4
5 5
6 6
7 7
Voila
Since you are using enumerate hence your i is actually the index of the key rather than the key itself.
So, you are getting 3 in the first column of the row 3 4even though there is no key 3.
enumerate iterates through a data structure(be it list or a dictionary) while also providing the current iteration number.
Hence, the columns here are the iteration number followed by the key in dictionary enum
Others Solutions have already shown how to iterate over key and value pair so I won't repeat the same in mine.
Iterating over a Python dict means to iterate over its keys exactly the same way as with dict.keys()
The order of the keys is determined by the implementation code and you cannot expect some specific order:
Keys and values are iterated over in an arbitrary order which is
non-random, varies across Python implementations, and depends on the
dictionary’s history of insertions and deletions. If keys, values and
items views are iterated over with no intervening modifications to the
dictionary, the order of items will directly correspond.
That's why you see the indices 0 to 7 in the first column. They are produced by enumerate and are always in the correct order. Further you see the dict's keys 0 to 7 in the second column. They are not sorted.
That sure must seem confusing. So this is what is going on. The first value of enumerate (in this case i) returns the next index value starting at 0 so 0, 1, 2, 3, ... It will always return these numbers regardless of what is in the dictionary. The second value of enumerate (in this case j) is returning the values in your dictionary/enumm (we call it a dictionary in Python). What you really want to do is what roadrunner66 responded with.
Python3:
One solution:
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, k in enumerate(enumm):
print("{}) d.key={}, d.value={}".format(i, k, enumm[k]))
Output:
0) enumm.key=0, enumm.value=1
1) enumm.key=1, enumm.value=2
2) enumm.key=2, enumm.value=3
3) enumm.key=4, enumm.value=4
4) enumm.key=5, enumm.value=5
5) enumm.key=6, enumm.value=6
6) enumm.key=7, enumm.value=7
An another example:
d = {1 : {'a': 1, 'b' : 2, 'c' : 3},
2 : {'a': 10, 'b' : 20, 'c' : 30}
}
for i, k in enumerate(d):
print("{}) key={}, value={}".format(i, k, d[k])
Output:
0) key=1, value={'a': 1, 'b': 2, 'c': 3}
1) key=2, value={'a': 10, 'b': 20, 'c': 30}
You may find it useful to include index inside key:
d = {'a': 1, 'b': 2}
d = {(i, k): v for i, (k, v) in enumerate(d.items())}
Output:
{(0, 'a'): True, (1, 'b'): False}
d = {0: 'zero', '0': 'ZERO', 1: 'one', '1': 'ONE'}
print("List of enumerated d= ", list(enumerate(d.items())))
output:
List of enumerated d= [(0, (0, 'zero')), (1, ('0', 'ZERO')), (2, (1, 'one')), (3, ('1', 'ONE'))]

Sort by column 1 and tuple(column2,column3) then expand again

I am new to Python and this seems to be a bit tricky for me:
I have 3 columns:
column1 : id
column2 : size
column3 : rank
I now want to re-align the id column and keeping size,rank in order together (size,rank)
so it would look like:
id:1 (size,rank):4,5
id:2 (size,rank):5,8
So the id column has to be reorded from 1 to 1000 and not messing up the (size,rank) tupel
I tried to do:
combined = zip(size,rank)
id, combined = zip(*sorted(zip(id, combined)))
Is this correct? And if yes, how can I seperate the tupel to 2 arrays size and rank again.
I heard about zip(*combined)?
unziped = zip(*combined)
then size equals unziped[0] and rank equals unziped[1] ?
Thank you for help!
ADDED from Numpy genfromtxt function
size= [x[2] for x in mydata]
rank= [x[1] for x in mydata]
Your main problem is you are using the id column as both an identifier and as the value by which the data is ordered. This is wrong. Leave the id column alone; and then sort the data by only size; once you have it sorted use enumerate to list the "order".
Here is an example, which sorts the data by the second column (size), then prints the data along with their "rank" or "order":
>>> data = ((1, 4, 5), (3, 6, 7), (4, 3, 3), (19, 32, 0))
>>> data_sorted = sorted(data, key=lambda x: x[1])
>>> for k,v in enumerate(data_sorted):
... print('{}: {}'.format(k+1, v))
...
1: (4, 3, 3)
2: (1, 4, 5)
3: (3, 6, 7)
4: (19, 32, 0)

Unsort a list back to original sequence

aList = [2, 1, 4, 3, 5]
aList.sort()
=[1, 2, 3, 4, 5]
del aList[2]
=[1, 2, 4, 5]
**unsort the list back to original sequence with '3' deleted**
=[2, 1, 4, 5]
In reality I have a list of tuples that contain (Price, Quantity, Total).
I want to sort the list, allow the user to delete items in the list and
then put it back in the original order minus the deleted items.
One thing to note is that the values in the tuples can repeat in the list,
such as:
aList = [(4.55, 10, 45.5), (4.55, 10, 45.5), (1.99, 3, 5.97), (1.99, 1, 1.99)]
You cannot unsort the list but you could keep the original unsorted index to restore positions.
E.g.
from operator import itemgetter
aList = [(4.55, 10, 45.5), (4.55, 10, 45.5), (1.99, 3, 5.97), (1.99, 1, 1.99)]
# In keyList:
# * every element has a unique id (it also saves the original position in aList)
# * list is sorted by some criteria specific to your records
keyList = sorted(enumerate(aList), key = itemgetter(1))
# User want to delete item 1
for i, (key, record) in enumerate(keyList):
if key == 1:
del keyList[i]
break
# "Unsort" the list
theList = sorted(keyList, key = itemgetter(0))
# We don't need the unique id anymore
result = [record for key, record in theList]
As you can see this works with duplicate values.
Unsorting can be done
This approach is like others - the idea is to keep the original indices to restore the positions. I wanted to add a clearer example on how this is done.
In the example below, we keep track of the original positions of the items in a by associating them with their list index.
>>> a = [4, 3, 2, 1]
>>> b = [(a[i], i) for i in range(len(a))]
>>> b
[(4, 0), (3, 1), (2, 2), (1, 3)]
b serves as a mapping between the list values and their indices in the unsorted list.
Now we can sort b. Below, each item of b is sorted by the first tuple member, which is the corresponding value in the original list.
>>> c = sorted(b)
>>> c
[(1, 3), (2, 2), (3, 1), (4, 0)]
There it is... sorted.
Going back to the original order requires another sort, except using the second tuple item as the key.
>>> d = sorted(c, key=lambda t: t[1])
>>> d
[(4, 0), (3, 1), (2, 2), (1, 3)]
>>>
>>> d == b
True
And now it's back in its original order.
One use for this could be to transform a list of non sequential values into their ordinal values while maintaining the list order. For instance, a sequence like [1034 343 5 72 8997] could be transformed to [3, 2, 0, 1, 4].
>>> # Example for converting a list of non-contiguous
>>> # values in a list into their relative ordinal values.
>>>
>>> def ordinalize(a):
... idxs = list(range(len(a)))
... b = [(a[i], i) for i in idxs]
... b.sort()
... c = [(*b[i], i) for i in idxs]
... c.sort(key=lambda item: item[1])
... return [c[i][2] for i in idxs]
...
>>> ordinalize([58, 42, 37, 25, 10])
[4, 3, 2, 1, 0]
Same operation
>>> def ordinalize(a):
... idxs = range(len(a))
... a = sorted((a[i], i) for i in idxs)
... a = sorted(((*a[i], i) for i in idxs),
... key=lambda item: item[1])
... return [a[i][2] for i in idxs]
You can't really do an "unsort", the best you can do is:
aList = [2, 1, 4, 3, 5]
aList.remove(sorted(aList)[2])
>>> print aList
[2, 1, 4, 5]
Try this to unsort a sorted list
import random
li = list(range(101))
random.shuffle(li)
Here's how I recommend to sort a list, do something, then unsort back to the original ordering:
# argsort is the inverse of argsort, so we use that
# for undoing the sorting.
sorter = np.argsort(keys)
unsorter = np.argsort(sorter)
sorted_keys = np.array(keys)[sorter]
result = do_a_thing_that_preserves_order(sorted_keys)
unsorted_result = np.array(result)[unsorter]
I had the same use case and I found an easy solution for that, which is basically random the list:
import random
sorted_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
unsorted_list = random.sample(sorted_list, len(sorted_list))

Categories