I know there is quite a number of similar questions on stackoverflow but they don't seem to be solving my problem. If you look at my code below, you can see that I am creating a temp list of ads called "tempAdList" and when the if condition evaluate true I am creating a list of lists called "ad_list". I am appending to "ad_list" so I am expecting that everytime the "if statement" evaluates true a new list of 4 ads is appended to "ad_list" but for whatever reason I am getting below output which is not what i am looking for. what am I doing wrong here?
ads = Advert.objects.all()
counter = 1
tempAdList = []
ad_list = []
for i, ad in enumerate(ads):
tempAdList.append(ad)
if counter == 4:
# print(tempAdList)
ad_list.append(tempAdList)
print(ad_list)
tempAdList.clear()
counter = 0
counter += 1
adsNum = len(ads)
# print("i = {} and adsNum = {}".format(i, adsNum))
if i == adsNum -1 and adsNum % 4 != 0:
ad_list.append(tempAdList)
output:
Using the clear-method on a list also affects all references to it, e.g.
>>a = [1, 2, 3]
>>b = a
>>a.clear()
>>print('a =',a)
a = []
>>print('b =',b)
b = []
So what you are doing in ad_list.append(tempAdList) is to repeatedly add references to the same object to ad_list, i.e. each time you update tempAdList, the same update is done for each of those references. What you really want to do is reset tempAdList with a new object, so replace tempAdList.clear() with tempAdList=[].
If you just want a list of lists, where inner lists are having 4 elements.
You can try something like :
new_list = [ads[i:i+4] for i in range(0, len(ads), 4)]
Every time you do tempAdlist.clear(), you cleared all elements of the list. But because you appended the list to ad_list, you basically cleared it there too. so you have one less list. This is because of the nature of lists being referenced instead of recreated. What you want is to create a list from tempAdlist when appending, like so: ad_list.append(list(tempAdlist)) this way it will be a whole new list from the tempAdlist. Essentially your code becomes:
ads = Advert.objects.all()
counter = 1
tempAdList = []
ad_list = []
for i, ad in enumerate(ads):
tempAdList.append(ad)
if counter == 4:
# print(tempAdList)
ad_list.append(list(tempAdList))
print(ad_list)
tempAdList.clear()
counter = 0
counter += 1
adsNum = len(ads)
# print("i = {} and adsNum = {}".format(i, adsNum))
if i == adsNum -1 and adsNum % 4 != 0:
ad_list.append(list(tempAdList))
Related
This is a part of my code, I am trying to fix the bug by running pdb. When I put actual print statement below, I can see the list elements but while running on pdb, it returns empty list and gives the error : ZeroDivisionError
def assign_clusters(data, k, initialization):
dim = data.shape
cluster = [[] for i in range(k)]
counter = 0
if initialization == 'round_robin':
if len(dim) == 1:
for i in range(0,dim[0]):
cluster[counter].append(data[i])
counter += 1
if counter == k:
counter = 0
means = mean_calculation(cluster)
lis = []
lis.append(cluster)
lis.append(means)
return lis
def mean_calculation(cluster):
means = [0 for j in range(len(cluster))]
for i in range(len(cluster)):
means[i] = sum(cluster[i])/len(cluster[i])
return means
lis = assign_clusters(out, k, initialization)
While trying to see the contents of lis using print(lis), I can see the list elements but not on pdb. Can you please help me out?
How do I code a function in python which can:
iterate through a list of word strings which may contain duplicate words and referencing to a dictionary,
find the word with the highest absolute sum, and
output it along with the corresponding absolute value.
The function also has to ignore words which are not in the dictionary.
For example,
Assume the function is called H_abs_W().
Given the following list and dict:
list_1 = ['apples','oranges','pears','apples']
Dict_1 = {'apples':5.23,'pears':-7.62}
Then calling the function as:
H_abs_W(list_1,Dict_1)
Should give the output:
'apples',10.46
EDIT:
I managed to do it in the end with the code below. Looking over the answers, turns out I could have done it in a shorter fashion, lol.
def H_abs_W(list_1,Dict_1):
freqW = {}
for char in list_1:
if char in freqW:
freqW[char] += 1
else:
freqW[char] = 1
ASum_W = 0
i_word = ''
for a,b in freqW.items():
x = 0
d = Dict_1.get(a,0)
x = abs(float(b)*float(d))
if x > ASum_W:
ASum_W = x
i_word = a
return(i_word,ASum_W)
list_1 = ['apples','oranges','pears','apples']
Dict_1 = {'apples':5.23,'pears':-7.62}
d = {k:0 for k in list_1}
for x in list_1:
if x in Dict_1.keys():
d[x]+=Dict_1[x]
m = max(Dict_1, key=Dict_1.get)
print(m,Dict_1[m])
try this,
key, value = sorted(Dict_1.items(), key = lambda x : x[1], reverse=True)[0]
print(f"{key}, {list_1.count(key) * value}")
# apples, 10.46
you can use Counter to calculate the frequency(number of occurrences) of each item in the list.
max(counter.values()) will give us the count of maximum occurring element
max(counter, key=counter.get) will give the which item in the list is
associated with that highest count.
========================================================================
from collections import Counter
def H_abs_W(list_1, Dict_1):
counter = Counter(list_1)
count = max(counter.values())
item = max(counter, key=counter.get)
return item, abs(count * Dict_1.get(item))
I am trying to append a list of 4 letters in my number as a [[a, b, c, d]] type of list.
I am looping through a list and appending the letter to a temp list and then appending it to my main list to make it into a matrix. However, the main list is only storing the number (8, 26) for some reason
ciphertext = "asfgasgsaga"
counter = 0
templist = []
xyz = []
for abc in ciphertext:
if(counter == 5):
print(templist)
xyz.append(templist)
templist.clear()
counter = 0
else:
templist.append(abc);
counter += 1
print(xyz)
The result is for some reason giving [[8, 26]]
The result is not the same as your expected because there some concepts that you need to know about objects in Python:
Immutable Objects: int, float, complex, string, tuple, frozen set, bytes. These kind of data types can't be changed the value after it is created. So that when we assign to another variable, it will copy the value to new variable. E.g:
a = 123
b = a
a = 456
print(b) #123
Mutable Objects: list, dict, set, byte array. These can be changed the value after it is created. And when you assign to another variable, it basically just assign the reference to previous variable like so:
a = []
b = a
a.append(123)
print(b) #[123]
So back to your problem, you're using list to create a list with 4 characters and then append it into another list, it's not append the expected list but instead a reference to it. That's why you got unexpected result.
And about the logic of your code, there are something go wrong, because when counter you will miss 1 character. You actually can switch to use slicing in Python:
ciphertext = "asfgasgsaga"
xyz = [ciphertext[start:start + 4] for start in range(0, len(ciphertext), 4)]
print(xyz) #['asfg', 'asgs', 'aga']
I'm using List Comprehension to append to xyz instead of call append function, create step like: 0:4, 4:8, 8:12, ... voila
Hope that helpful for you.
Just as #zvone says, don's use the same array and clear it, because they ref the same memory;
ciphertext = "asfgasgsaga"
counter = 0
templist = []
xyz = []
for abc in ciphertext:
if(counter == 4):
print(templist)
xyz.append(templist)
templist = [] # <--- use a new empty array
counter = 0
else:
templist.append(abc);
counter += 1
print(xyz)
Also, the correct logic(handle the letters less than 4) should be:
ciphertext = "asfgasgsaga"
counter = 0
templist = []
xyz = []
for abc in ciphertext:
templist.append(abc);
counter += 1
if(counter == 4):
print(templist)
xyz.append(templist)
templist = []
counter = 0
if templist:
xyz.append(templist)
print(xyz)
Just see #Toan Quoc Ho's answer, which should make more sense. Just leave the answer here to compare your origin logic.
I coded this on Python. It took way too long to finish if the input were just 40x40 (it's for image processing using numpy). Its behavious is the following: there's an array with objects in it (which have an 'image' attribute which is a numpy array) and then I check if that object is somewhere in another array, and then take the next from the first array and repeat the process until I've checked if all are in the other array:
#__sub_images is the array containing the objects to be compared
#to_compare_image is the image that is received as parameter to check if the objects are in there.
#get_sub_images() is just to retrieve the objects from the array from the received array to find.
#get_image() is the method that retrieves the attribute from the objects
same = True
rows_pixels = 40 #problem size
cols_pixels = 40 #problem size
i = 0 #row index to move the array containing the object that must be checked if exist
j = 0 #col index to move the array containing the object that must be checked if exist
k = 0 #row index to move the array where will be checked if the object exist
l = 0 #col index to move the array where will be checked if the object exist
while i < len(self.__sub_images) and k < len(to_compare_image.get_sub_images()) and l < len(to_compare_image.get_sub_images()[0]):
if not np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image()):
same = False
else:
same = True
k = 0
l = 0
if j == len(self.__sub_images[0]) - 1:
j = 0
i += 1
else:
j += 1
if not same:
if l == len(to_compare_image.get_sub_images()[0]) - 1:
l = 0
k += 1
else:
l += 1
I managed to code it with just a while, instead of 4 for-loops which is what I used to do before. Why is it taking so long still? Is it normal or is there something wrong? The complexity is supposed to be x and not x⁴
The code that is not included are just getters, I hope you can understand it with the #notes at the begining.
THanks.
Instead of this:
if not np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image()):
same = False
else:
same = True
#snip
if not same:
#snip
You can do this:
same=np.array_equal(self.__sub_images[i][j].get_image(), to_compare_image.get_sub_images()[k][l].get_image())
if same:
#snip
else:
#snip
This uses less if-branches than before.
I have a list containing strings as ['Country-Points'].
For example:
lst = ['Albania-10', 'Albania-5', 'Andorra-0', 'Andorra-4', 'Andorra-8', ...other countries...]
I want to calculate the average for each country without creating a new list. So the output would be (in the case above):
lst = ['Albania-7.5', 'Andorra-4.25', ...other countries...]
Would realy appreciate if anyone can help me with this.
EDIT:
this is what I've got so far. So, "data" is actually a dictionary, where the keys are countries and the values are list of other countries points' to this country (the one as Key). Again, I'm new at Python so I don't realy know all the built-in functions.
for key in self.data:
lst = []
index = 0
score = 0
cnt = 0
s = str(self.data[key][0]).split("-")[0]
for i in range(len(self.data[key])):
if s in self.data[key][i]:
a = str(self.data[key][i]).split("-")
score += int(float(a[1]))
cnt+=1
index+=1
if i+1 != len(self.data[key]) and not s in self.data[key][i+1]:
lst.append(s + "-" + str(float(score/cnt)))
s = str(self.data[key][index]).split("-")[0]
score = 0
self.data[key] = lst
itertools.groupby with a suitable key function can help:
import itertools
def get_country_name(item):
return item.split('-', 1)[0]
def get_country_value(item):
return float(item.split('-', 1)[1])
def country_avg_grouper(lst) :
for ctry, group in itertools.groupby(lst, key=get_country_name):
values = list(get_country_value(c) for c in group)
avg = sum(values)/len(values)
yield '{country}-{avg}'.format(country=ctry, avg=avg)
lst[:] = country_avg_grouper(lst)
The key here is that I wrote a function to do the change out of place and then I can easily make the substitution happen in place by using slice assignment.
I would probabkly do this with an intermediate dictionary.
def country(s):
return s.split('-')[0]
def value(s):
return float(s.split('-')[1])
def country_average(lst):
country_map = {}|
for point in lst:
c = country(pair)
v = value(pair)
old = country_map.get(c, (0, 0))
country_map[c] = (old[0]+v, old[1]+1)
return ['%s-%f' % (country, sum/count)
for (country, (sum, count)) in country_map.items()]
It tries hard to only traverse the original list only once, at the expense of quite a few tuple allocations.