Dynamically append sliced list items to a dictionary in python - python

I have a result dictionary with pre-defined keys that should be populated based on slices of an array without explicitly accessing the dictionary keys, below is an example of my approach
my_list = ['a','b','c','d','e']
my_dict = {'first_item':'', 'middle_items':'','last_item':''}
for key in my_dict.keys():
value = my_list.pop()
my_dict.update({k:''.join(value)})
This approach obviously does not work because pop does not slice the array. And if I want to use slicing, I will have to explicitly access the dictionary variables and assign the corresponding list slices.
I have tried using the list length to slice through the list, but was unable to find a general solution, here is my other approach
for key in my_dict.keys():
value = ''.join(my_list[:-len(my_list)+1])
del my_list[0]
my_dict.update({k:v})
How can I slice a list in a general way such that it splits into a first item, last item, and middle items? below is how the updated dictionary should look like
my_dict = {'first_item':'a', 'middle_items':'b c d','last_item':'e'}
Edit: if I use [0],[1:-1], and [-1] slices then that means that I will have to access each dictionary key individually and update it rather than loop over it (which is the desired approach)

If you are using python 3 then you should try this idiom:
my_list = ['a','b','c','d','e']
first_item, *middle_items, last_item = my_list
my_dict = dict(
first_item=first_item,
middle_items=' '.join(middle_items),
last_item=last_item
)
print(my_dict)
# {'last_item': 'e', 'middle_items': 'b c d', 'first_item': 'a'}

To get a slice of my_list, use the slice notation.
my_list = ['a', 'b', 'c', 'd', 'e']
my_dict = {
'first_item': my_list[0],
'middle_items': ' '.join(my_list[1:-1]),
'last_item': my_list[-1]
}
Output
{'first_item': 'a',
'middle_items': 'b c d',
'last_item': 'e'}

Related

Adding html tags with regex/python, sub code not working [duplicate]

Now I know that it is not safe to modify the list during an iterative looping. However, suppose I have a list of strings, and I want to strip the strings themselves. Does replacement of mutable values count as modification?
See Scope of python variable in for loop for a related problem: assigning to the iteration variable does not modify the underlying sequence, and also does not impact future iteration.
Since the loop below only modifies elements already seen, it would be considered acceptable:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Which is different from:
a[:] = [s.strip() for s in a]
in that it doesn't require the creation of a temporary list and an assignment of it to replace the original, although it does require more indexing operations.
Caution: Although you can modify entries this way, you can't change the number of items in the list without risking the chance of encountering problems.
Here's an example of what I mean—deleting an entry messes-up the indexing from that point on:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(The result is wrong because it didn't delete all the items it should have.)
Update
Since this is a fairly popular answer, here's how to effectively delete entries "in-place" (even though that's not exactly the question):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
See How to remove items from a list while iterating?.
It's considered poor form. Use a list comprehension instead, with slice assignment if you need to retain existing references to the list.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
One more for loop variant, looks cleaner to me than one with enumerate():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
Modifying each element while iterating a list is fine, as long as you do not change add/remove elements to list.
You can use list comprehension:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
or just do the C-style for loop:
for index, item in enumerate(l):
l[index] = item.strip()
The answer given by Ignacio Vazquez-Abrams is really good. It can be further illustrated by this example. Imagine that:
A list with two vectors is given to you.
You would like to traverse the list and reverse the order of each one of the arrays.
Let's say you have:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # This command does not reverse the string.
print([v,b])
You will get:
[array([1, 2, 3, 4]), array([3, 4, 6])]
On the other hand, if you do:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # This command reverses the string.
print([v,b])
The result is:
[array([4, 3, 2, 1]), array([6, 4, 3])]
No you wouldn't alter the "content" of the list, if you could mutate strings that way. But in Python they are not mutable. Any string operation returns a new string.
If you had a list of objects you knew were mutable, you could do this as long as you don't change the actual contents of the list.
Thus you will need to do a map of some sort. If you use a generator expression it [the operation] will be done as you iterate and you will save memory.
You can do something like this:
a = [1,2,3,4,5]
b = [i**2 for i in a]
It's called a list comprehension, to make it easier for you to loop inside a list.
It is not clear from your question what the criteria for deciding what strings to remove is, but if you have or can make a list of the strings that you want to remove , you could do the following:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
which changes my_strings to ['a', 'c', 'e']
In short, to do modification on the list while iterating the same list.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
example:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]
Something I just discovered - when looping over a list of mutable types (such as dictionaries) you can just use a normal for loop like this:
l = [{"n": 1}, {"n": 2}]
for d in l:
d["n"] += 1
print(l)
# prints [{"n": 2}, {"n": 1}]

Identify distinct elements in a list and map it to a corresponding index in another list in python

I have 2 different lists:
l1 = ['a','b','a','e','b','c','a','d']
l2 = ['t1','t2','t3','t4','t5','t6','t7','t8']
The lengths of l1 and l2 will always be the same. They're in fact logical mappings - each item in l1 corresponds to a value in l2.
I wanted to identify distinct elements in l1. I did that using set and list comprehension as follows:
used = set()
distl1 = [x for x in l1 if x not in used and (used.add(x) or True)]
Here, the output will be:
distl1 = ['a','b','e','c','d']
which is nothing but the first occurrence of every distinct element.
Now, how do I build a list distl2 so that I get the output as the value in l2 that corresponds to the first occurrence's value i.e., distl1?
distl2 = ['t1','t2','t4','t6','t8']
My idea is to use an OrderedDict to build a mapping of (key, value) pairs corresponding to the elements of l1 and l2 and then extract the values from that dict as a list.
>>> from collections import OrderedDict
>>>
>>> l1 = ['a','b','a','e','d','c','a','b']
>>> l2 = ['t1','t2','t3','t4','t5','t6','t7','t8']
>>>
>>> d = OrderedDict()
>>> for k, v in zip(l1, l2):
...: if k not in d: # <--- check if this key has already been seen!
...: d[k] = v
...:
>>> distl2 = list(d.values())
>>> distl2
>>> ['t1', 't2', 't4', 't5', 't6']
Note for Python 3.7+ users: regular dicts are guaranteed to remember their key insertion order, so you can omit importing the OrderedDict.
You can also do this:
distl2 = [l2[l1.index(key)] for key in distl1]
Python 3.6+
Dictionaries are ordered in Python 3.6+, as an implementation detail in 3.6 and confirmed in 3.7+. So in this case you can use dict with an iterable which ignores duplicates. To ignore duplicates, you can use the itertools unique_everseen recipe, also available via 3rd party more_itertools.unique_everseen or toolz.unique:
from operator import itemgetter
from toolz import unique
l1 = ['a','b','a','e','b','c','a','d']
l2 = ['t1','t2','t3','t4','t5','t6','t7','t8']
keys, values = zip(*dict(unique(zip(l1, l2), key=itemgetter(0))).items())
print(keys)
('a', 'b', 'e', 'c', 'd')
print(values)
('t1', 't2', 't4', 't6', 't8')
Python 2.7
You can use collections.OrderedDict instead of dict for Python 2.7, where dictionaries are not ordered:
from collections import OrderedDict
keys, values = zip(*OrderedDict(unique(zip(l1, l2), key=itemgetter(0))).items())
The question doesn't say if you need to preserve the order. If not, list of unique values of l1 would be:
distl1 = list(set(l1))
And the corresponding values of l2:
distl2 = [l2[l1.index(value)] for value in distl1]
(where index() always returns the first occurrence)
The resulting lists will keep your logical mapping, in the random order:
['b', 'e', 'c', 'd', 'a']
['t2', 't4', 't6', 't8', 't1']
EDIT:
Another approach (no dictionaries, no index() in a loop, order preserved, 2.7 friendly):
l1 = ['a','b','a','e','b','c','a','d']
l2 = ['t1','t2','t3','t4','t5','t6','t7','t8']
distl1 = []
distl2 = []
for i, val in enumerate(l1):
if val not in distl1:
distl1.append(val)
distl2.append(l2[i])

How to arrange the output of set based on predefined list

list1=['f','l','a','m','e','s'] #This is the predefined list
list2=['e','e','f','a','s','a'] #This is the list with repitition
x=list(set(list2)) # I want to remove duplicates
print(x)
Here I want the variable x to retain the order which list1 has. For example, if at one instance set(list2) produces the output as ['e','f','a','s'], I want it to produce ['f','a','e','s'] (Just by following the order of list1).
Can anyone help me with this?
Construct a dictionary that maps characters to their position in list1. Use its get method as the sort-key.
>>> dict1 = dict(zip(list1, range(len(list1))))
>>> sorted(set(list2), key=dict1.get)
['f', 'a', 'e', 's']
This is one way using dictionary:
list1=['f','l','a','m','e','s'] #This is the predefined list
list2=['e','e','f','a','s','a'] #This is the list with repitition
x=list(set(list2)) # I want to remove duplicates
d = {key:value for value, key in enumerate(list1)}
x.sort(key=d.get)
print(x)
# ['f', 'a', 'e', 's']
Method index from the list class can do the job:
sorted(set(list2), key=list1.index)
What is best usually depends on actual use. With this problem it is important to know the expected sizes of the lists to choose the most efficient approach. If we are keeping much of the dictionary the following query works well and has the additional benefit that it is easy to read.
set2 = set(list2)
x = [i for i in list1 if i in set2]
It would also work without turning list2 into a set first. However, this would run much slower with a large list2.

Remove element in list using list comprehension - Python

I have a list like this:
['A','B','C']
What I need is to remove one element based on the input I got in the function. For example, if I decide to remove A it should return:
['B','C']
I tried with no success
list = ['A','B','C']
[var for var in list if list[var] != 'A']
How can I do it?
Thanks
Simple lst.remove('A') will work:
>>> lst = ['A','B','C']
>>> lst.remove('A')
['B', 'C']
However, one call to .remove only removes the first occurrence of 'A' in a list. To remove all 'A' values you can use a loop:
for x in range(lst.count('A')):
lst.remove('A')
If you insist on using list comprehension you can use
>>> [x for x in lst if x != 'A']
['B', 'C']
The above will remove all elements equal to 'A'.
The improvement to your code (which is almost correct) would be:
list = ['A','B','C']
[var for var in list if var != 'A']
However, #frostnational's approach is better for single values.
If you are going to have a list of values to disallow, you can do that as:
list = ['A','B','C', 'D']
not_allowed = ['A', 'B']
[var for var in list if var not in not_allowed]
If you not sure whether the element exists or not, you might want to check before you delete:
if 'A' in lst:
lst.remove('A')
Find this simplified code:
list1 = [12,24,35,24,88,120,155]
while 24 in list1:
list1.remove(24)
print(list1)
Best Luck!
originalList=['A','B','C']
print([val for val in originalList if val!='A'])
This prints
['B', 'C']
You can just use the remove method of list. Just do list.remove('A') and it will be removed.
If you have the index of the item to be removed, use the pop method. list.pop(0).
You were really close:
list = ['A','B','C']
[var for var in list if list[list.index(var)] != 'A']
You tried to refer to a list item using a syntax that calls for an index value.

python / sets / dictionary / initialization

Can someone explain help me understand how the this bit of code works? Particularly how the myHeap assignment works. I know the freq variable is assigned as a dictionary. But what about my myHeap? is it a Set?
exe_Data = {
'e' : 0.124167,
't' : 0.0969225,
'a' : 0.0820011,
'i' : 0.0768052,
}
freq = exe_Data)
myHeap = [[pct, [symbol, ""]] for symbol, pct in freq.items()]
freq is a reference to the dictionary, as you said.
myHeap is constructed using a list comprehension, and so it is a list. The general form of a list comprehension is:
[ expr for x in iterable ]
So myHeap will be a list, each element of which is a list with the first element being the value of the corresponding dictionary entry, and the second element being another list whose first element is the corresponding key of the dictionary, and whose second element is "".
There are no sets in your given code sample.
You can see this working like so (I edited the number output for readability):
>>> [ symbol for symbol, pct in freq.items() ]
['a', 'i', 'e', 't']
>>> from pprint import pprint # Yay, pretty printing
>>> pprint([ [pct, symbol] for symbol, pct in freq.items() ])
[[0.0820011, 'a'],
[0.0768052, 'i'],
[0.1241670, 'e'],
[0.0969225, 't']]
>>> pprint([ [pct, [symbol, ""]] for symbol, pct in freq.items() ])
[[0.0820011, ['a', '']],
[0.0768052, ['i', '']],
[0.1241670, ['e', '']],
[0.0969225, ['t', '']]]
Note that, since dictionaries in Python don't preserve the order of their elements, there's no guarantee what order the freq elements will end up being in in myHeap.
exe_Data = {
'e' : 0.124167,
't' : 0.0969225,
'a' : 0.0820011,
'i' : 0.0768052,
}
The above code creates a dictionary called 'exe_Data'. Another way to do this is to use the built-in constructor, dict() with keyword arguments as follows: exe_Data = dict(e=0.12467, t=0.0969225, a=0.0820011, i=0.0768052)
freq = exe_Data)
I think the above bit should read freq=exe_Data. It makes another reference to the dictionary created in the previous bit.
myHeap = [[pct, [symbol, ""]] for symbol, pct in freq.items()]
This last part creates a list using a list comprehension. It creates a list of lists of two things, The first thing is a key from the dictionary created and referenced above, and the second thing is a list containing the corresponding value from the dictionary and a blank string.
EDIT:
In answer to the comment, it would be the equivalent of writing:
myHeap = []
for key, val in freq.items():
myHeap.append([key, [val, ""]])
I assume you meant
freq = exe_Data
In this case, myHeap will look like this:
[ [0.124167, ['e', ""]],
[0.0969225, ['t', ""]],
[0.0820011, ['a', ""]],
[0.0768052, ['i', ""]]
]
Note that the order here is arbitrary, but I wanted to write it plainly so you can see what you have in the end results.
Basically it just changes the order of your key/value of your dictionary, and puts the key in a sub-array for some reason.

Categories

Resources