There is a list with elements of similar nature (4 7's,3 5's, etc.) that I want to insert in right left order into a another list ().
newlst = []
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
So the first thing being inserted into newlst is the group of 7's:
newlst = [7,7,7,7]
Subsequently, the group of 5's is inserted into the list on the right:
newlst = [7, 7, 7, 7, 5, 5, 5]
And then the group of 3's is inserted on the left, and after that the group of 2's is inserted on the right. The final list looks like this
newlst = [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]
In order to add elements in the list on a right left basis, I did this:
for i in lst:
lst.insert(0,i)
else:
lst.append(i)
The insert method inserts elements into the 0 index (which is the right of the list) and append adds elements at the end of the list (which is the left of the list). However, I'm having problems adding the group of elements into the newlst. To that end, I thought using a dictionary would be a good idea.
myDict = {2: 2, 3: 3, 5: 3, 7: 4}
EDIT:
for k, v in myDict.items():
if k in lst:
for i in range(v):
lst.append(i)
else:
lst.insert(0,i)
The intention of this dictionary is for each key, I want to insert the key value 'x' times, e.g. the key 7, would be inserted 4 times: [7,7,7,7]. Is there a way to achieve this in Python so I can get the output newlist: [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2] ?
You can accomplish this pretty easily with a deque, along with cycle and groupby
from collections import deque
from itertools import groupby, cycle
#creates a deque object
d = deque()
#creates a repeating iterator to alternate function calls
c = cycle([d.extendleft, d.extend])
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
for _, items in groupby(lst):
#calls the alternated function to extend the items
next(c)(items)
print(list(d))
>>> [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]
Here is your initial code:
newlst = []
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
myDict = {2: 2, 3: 3, 5: 3, 7: 4}
for k, v in myDict.items():
if k in lst:
for i in range(v):
lst.append(i)
else:
lst.insert(0,i)
You have a few major problems here:
k is always in lst, by definition. That means your check is not a valid way to alternate.
Your data is getting appended/prepended to lst instead of newlst.
A dict is a hash-table. This means that the order of the keys will pretty much never be in the order you defined them in.
The first item can be solved through enumeration:
for i, (k, v) in enumerate(myDict.items()):
if i % 2:
newlst = [k] * v + newlst
else:
newlst += [k] * v
I've fixed the list you are appending to, and am using [k] * v to construct the prepended/appended list. newlst += [k] * v is equivalent to newlst.extend([k] * v). However, keep in mind that newlst = [k] * v + newlst creates a new list object rather than concatenating in-place.
The third item can be fixed using OrderedDict instead of a regular dict:
from collections import OrderedDict
...
myDict = OrderedDict([(2, 2), (3, 3), (5, 3), (7, 4)])
That will make the keys run in the order that you want. In fact, you don't need to construct myDict by hand at all. You can combine OrderedDict with a Counter to get the exact same result dynamically. The recipe for this is given in the OrderedDict docs:
from collections import Counter, OrderedDict
...
class OrderedCounter(Counter, OrderedDict):
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
myDict = OrderedCounter(lst)
All this is pretty verbose and not very efficient. As #Wondercricket's answer points out, you can use the functions in itertools to perform the same task using generators.
This is what you want to do?
list = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
def list_to_answerlist(list, default=[]):
if not list:
return default
else:
result = []
direction = True # Insert Direction: True = Insert Left / False = Insert Right
actual_group = list[0]
for element in list:
if (element != actual_group):
direction = not direction # Change Insert Direction
actual_group = element # Update Actual Group
if direction: # Insert Left
result.insert(0,element)
else: # Insert Right
result.append(element)
return result
new_list = list_to_answerlist(list) # output = [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]
Related
My objective is to convert a list to a dictionary with the keys being the variable name of the list and the index value of the list attached to each key. It needs to be generically viable in the form of a function (since I have many lists that need to be converted to key-value pairs). For example, say I have these two lists:
action = [1, 3, 5, 7, 9]
result = [2, 6, 10, 14, 18]
and I have a function:
def list_to_dict(lst):
...
return dict
The output should be something like this:
action_dict = list_to_dict(action)
result_dict = list_to_dict(result)
print(action_dict)
print(result_dict)
>>> {'action_0': 1, 'action_1': 3, 'action_2': 5, 'action_3': 7, 'action_4': 9}
>>> {'result_0': 2, 'result_1': 6, 'result_2': 10, 'result_3': 14, 'result_4': 18}
So far, all I am able to do for the function is enumerate a list and have the index be the key to the respective values.
def list_to_dict(lst):
dict = {k:v for k, v in enumerate(lst)}
return dict
>>> {0: 1, 1: 3, 2: 5, 3: 7, 4: 9}
However, I am unable to find a way to have the variable name be in the key as a string. I tried var.__name__ but I think that is limited to functions.
Using retrieve_name by juan Isaza from Getting the name of a variable as a string
import inspect
action = [1, 3, 5, 7, 9]
result = [2, 6, 10, 14, 18]
def retrieve_name(var):
"""
Gets the name of var. Does it from the out most frame inner-wards.
:param var: variable to get name from.
:return: string
"""
for fi in reversed(inspect.stack()):
names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
if len(names) > 0:
return names[0]
def list_to_dict(lst):
name = retrieve_name(lst)
return {f"{name}_{k}":v for k, v in enumerate(lst)}
action_dict = list_to_dict(action)
result_dict = list_to_dict(result)
print(action_dict)
print(result_dict)
Output:
{'action_0': 1, 'action_1': 3, 'action_2': 5, 'action_3': 7, 'action_4': 9}
{'result_0': 2, 'result_1': 6, 'result_2': 10, 'result_3': 14, 'result_4': 18}
you can use zip as below
dic = {k:v for k,v in zip(action,result)}
I have a below method that finds the non-repeating elements in a list:
def dupes(a):
s = {}
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
for x in s:
if s[x] == 1:
return 'this is the only non-repeating element value is :', s[x], 'and the key is :', x
return
l = [4, 7, 4, 5, 7, 6, 5, 6, 10]
cd = dupes(l)
print("This is dupes: ", cd)
The code runs successfully and below is the output:
This is dupes: ('this is the only non-repeating element value is :', 1, 'and the key is :', 10)
But when I am trying to add more than one non-repeating elements in the list, the output doesn't change. For example, if I add 11 at the end of the list the output still remains the same as above..
Any idea?
Actually when you return at the 10th line, the function ends. This is in case you don't understand the list comprehension yet, as many have given you the solution with that technique. I will just give you a simple solution where it will return a list of non-repeating numbers.
def dupes(a):
s = {}
non_dupes = []
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
for x in s:
if s[x] == 1:
non_dupes.append(x)
return non_dupes
l = [4, 7, 4, 5, 7, 6, 5, 6, 10, 11]
cd = dupes(l)
print("This is dupes: ", cd)
def dupes(a):
s = {}
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
count = 0
keys = []
for x in s:
if s[x] == 1:
count += 1
keys.append(x)
return 'this is the only non-repeating element value is :', count, 'and the key is :', keys
That would be fine.
You can get all keys whose value is 1 using a list comprehension.
nondupes = [k for (k,v) in s.items() if v==1]
return 'Non-repeating elements: ' + str(nondupes)
Also, you could replace all your counting code with a collections.Counter:
s = Counter(a)
You can easely solve this in one line of python code, using the count() function:
l = [4, 7, 4, 5, 7, 6, 5, 6, 10 ,11]
only_one_time = [e for e in l if l.count(e) < 2]
print(only_one_time)
The given code returns the first non-repeating element it encounters.
For example,
if the input list is l = [12, 11, 4, 7, 4, 5, 7, 6, 5, 6, 10],
the output would be This is dupes: ('this is the only non-repeating element value is :', 1, 'and the key is :', 12).
You can succinctly achieve the above with Counter:
from collections import Counter
l = [4, 7, 4, 5, 7, 6, 5, 6, 10]
c = Counter(l)
dupes = list(key for key in c if c[key] > 1)
print("This is dupes: ", dupes)
Output:
This is dupes: [4, 7, 5, 6]
The issue that you are encountering is that you are returning prematurely from your function with a string containing the first duplicate. The rest of the duplicates are lost.
You already have the list of duplicates, let's return just the data so we can separate the calculation of results from the display of results.
return list(e for e in s if s[e] > 1)
How can I fix my code to pass the test case for Delete occurrences of an element if it occurs more than n times?
My current code pass one test case and I'm sure that the problem is caused by order.remove(check_list[i]).
However, there is no way to delete the specific element with pop() because it is required to put an index number rather than the element in pop().
Test case
Test.assert_equals(delete_nth([20,37,20,21], 1), [20,37,21])
Test.assert_equals(delete_nth([1,1,3,3,7,2,2,2,2], 3), [1, 1, 3, 3, 7, 2, 2, 2])
Program
def delete_nth(order, max_e):
# code here
check_list = [x for x in dict.fromkeys(order) if order.count(x) > 1]
print(check_list)
print(order)
for i in range(len(check_list)):
while(order.count(check_list[i]) > max_e):
order.remove(check_list[i])
#order.pop(index)
return order
Your assertions fails, because the order is not preserved. Here is a simple example of how this could be done without doing redundant internal loops to count the occurrences for each number:
def delete_nth(order, max_e):
# Get a new list that we will return
result = []
# Get a dictionary to count the occurences
occurrences = {}
# Loop through all provided numbers
for n in order:
# Get the count of the current number, or assign it to 0
count = occurrences.setdefault(n, 0)
# If we reached the max occurence for that number, skip it
if count >= max_e:
continue
# Add the current number to the list
result.append(n)
# Increase the
occurrences[n] += 1
# We are done, return the list
return result
assert delete_nth([20,37,20,21], 1) == [20, 37, 21]
assert delete_nth([1, 1, 1, 1], 2) == [1, 1]
assert delete_nth([1, 1, 3, 3, 7, 2, 2, 2, 2], 3) == [1, 1, 3, 3, 7, 2, 2, 2]
assert delete_nth([1, 1, 2, 2], 1) == [1, 2]
A version which maintains the order:
from collections import defaultdict
def delete_nth(order, max_e):
count = defaultdict(int)
delet = []
for i, v in enumerate(order):
count[v] += 1
if count[v] > max_e:
delet.append(i)
for i in reversed(delet): # start deleting from the end
order.pop(i)
return order
print(delete_nth([1,1,2,2], 1))
print(delete_nth([20,37,20,21], 1))
print(delete_nth([1,1,3,3,7,2,2,2,2], 3))
This should do the trick:
from itertools import groupby
import numpy as np
def delete_nth(order, max_e):
if(len(order)<=max_e):
return order
elif(max_e<=0):
return []
return np.array(
sorted(
np.concatenate(
[list(v)[:max_e]
for k,v in groupby(
sorted(
zip(order, list(range(len(order)))),
key=lambda k: k[0]),
key=lambda k: k[0])
]
),
key=lambda k: k[1])
)[:,0].tolist()
Outputs:
print(delete_nth([2,3,4,5,3,2,3,2,1], 2))
[2, 3, 4, 5, 3, 2, 1]
print(delete_nth([2,3,4,5,5,3,2,3,2,1], 1))
[2, 3, 4, 5, 1]
print(delete_nth([2,3,4,5,3,2,3,2,1], 3))
[2, 3, 4, 5, 3, 2, 3, 2, 1]
print(delete_nth([2,2,1,1], 1))
[2, 1]
Originally my answer only worked for one test case, this is quick (not the prettiest) but works for both:
def delete_nth(x, e):
x = x[::-1]
for i in x:
while x.count(i) > e:
x.remove(i)
return x[::-1]
You are given an array of numbers. Print the least occurring element. If there is more than 1 element print all of them in decreasing order of their value.
Input:
[9, 1, 6, 4, 56, 56, 56, 6, 4, 2]
Output:
[9, 2, 1]
I actually got output but doesn't execute private cases, please help me.
from collections import Counter
n=int(input())
ans=""
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.reverse()
for i in list2:
ans+=str(i)+' '
print(ans[:-1])
I see a lot of complicated answers. It can actually be done by just using list comprehension over the items in the instance of Counter():
>>> from collections import Counter
>>> count = Counter([9, 1, 6, 4, 56, 56, 56, 6, 4, 2])
>>> values = [key for key, value in count.items() if value == min(count.values())]
>>> values.sort(reverse=True) # [9, 2, 1]
The reason you are getting error is because Counter/Dictionary is an unordered collection. So your list2 could have elements in a different order each time you run it. Try running your code for [9, 1, 6, 4, 56, 6, 4, 2] input.
from collections import Counter
n=int(input())
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.sort(reverse=True)
print(' '.join(str(i) for i in list2))
Without any import you can also try
def getAllindex(lst, elem):
return list(filter(lambda a: lst[a] == elem, range(0,len(lst))))
lst = [9, 1, 6, 4, 56, 56, 56, 6, 4, 2]
list_count = [lst.count(xx) for xx in lst]
idx = getAllindex(list_count, min(list_count))
l = list(set([lst[ii] for ii in idx]))
l.sort(reverse = True)
print(l)
Output
[9, 2, 1]
You can do this by simply sorting the list before reversing it. and you need not create a string for list . simply *list_name and it will print list using spaces.
from collections import Counter
n=int(input())
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.sort(reverse=True)
print(*list2)
I have a dictionary in python with several lists, and what I try to do is get a list of tuples (or lists) where the lists are grouped with the same elements regardless of whether they are ordered. For example:
dict_1 = {
"pv_0": [1, 2, 3, 4, 5],
"pv_1": [2, 4, 6, 8, 10],
"pv_2": [1, 3, 5, 7, 9],
"pv_3": [3, 4, 1, 2, 5],
"pv_4": [2, 3, 4, 5, 6],
"pv_5": [3, 4, 5, 6, 2],
"pv_6": [1, 2, 3, 5, 4],
"pv_7": [5, 9, 7, 3, 1],
"pv_8": [2, 4, 6, 8, 10],
"pv_9": [1, 3, 5, 6, 7],
}
I wish to obtain the following result:
Result = [
("pv_0", "pv_3", "pv_6"),
("pv_2", "pv_7"),
("pv_1", "pv_8"),
("pv_4", "pv_5"),
("pv_9"),
]
How do I solve this problem?
from operator import itemgetter
from itertools import groupby
# create a new dictionary where the value is a hashed immutable set
d = {k: hash(frozenset(v)) for k, v in dict_.items()}
{'pv_0': -3779889356588604112,
'pv_1': 2564111202014126800,
'pv_2': 777379418226018803,
'pv_3': -3779889356588604112,
'pv_4': 8713515799959436501,
'pv_5': 8713515799959436501,
'pv_6': -3779889356588604112,
'pv_7': 777379418226018803,
'pv_8': 2564111202014126800,
'pv_9': -6160949303479789752}
first = itemgetter(0) # operator to grab first item of iterable
second = itemgetter(1) # operator to grab second item of iterable
[list(map(first, v)) for _, v in groupby(sorted(d.items(), key=second), key=second)]
[['pv_9'],
['pv_0', 'pv_3', 'pv_6'],
['pv_2', 'pv_7'],
['pv_1', 'pv_8'],
['pv_4', 'pv_5']]
The final list comprehension grabs all the key/value pairs from the dictionary and sorts them by the value. It then passes that in to the groupby function from itertools and tells it to group by the value of the dictionary. The output of this is then fed in to a map function which grabs the first item from each pair in the group which would be the corresponding key.
From what I can tell, you want a tuple of keys where each value is the same.
def get_matching_keys(data: dict) -> list:
# first, make everything a set
for key in data:
data [key] = set (data [key]) # makes order irrelevant
results = []
duplicates = []
for key, value in data.items():
if key in duplicates: continue # we already did this
result = [key]
duplicates.append (key)
for key2, value2 in data.items():
if key == key2: continue # skip the same key
else:
if value == value2:
result.append (key2)
duplicates.append (key2) # make sure we don't do it again
results.append (result)
return results