dict does not contain the expected number of items - python

I'm writing a program to iterate through a long number, converting it into a string, and then using an index list to pick out 10 individual consecutive numbers from the long number, then multiplying those ten numbers together and adding the numbers and the result to a dictionary. Then I am increasing the index list values by 1, and repeating the process until I have run through the whole number.
Then I am trying to find the largest value in the dictionary, and have the program tell me that value.
The problem I am having is that I have an error checking mechanism in the program, which tells me how many key/value pairs I have in the dictionary. It should be 990, but instead I have 53.
If anyone can identify what the problem is, I will be eternally grateful.
Code to follow:
from functools import reduce
#define the number to test
testno = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
#declare initial variables
index=[]
products = {}
count = 0
#define functions
def product(x):
return reduce((lambda a,b: a*b),x)
def increm(y):
return [x+1 for x in y]
#def runproduct(x):
# return product
def testnos(x):
return [int(str(x)[y]) for y in index]
#define the initial index
for x in range(10):
index = index+[x]
runtime = len(str(testno))-10
#start the while loop
while count < runtime:
products[str(testnos(testno))] = product(testnos(testno))
index = increm(index)
count+=1
print("[+] Number of results: "+str(len(str(products.values))))
print("[+] The numbers with the largest product are: "+str(max(products.keys(),key=(lambda k:products[k]))))

You have a problem in your first print statement. You are currently converting your products into a string, which returns to you something like this
{'[0, 8, 1, 3, 5, 3, 3, 6, 2, 7]': 0, ..., '[7, 8, 4, 6, 8, 6, 2, 2, 4, 8]': 8257536}
Applying the len built-in over it will return the result 53. What you really want here is calling len directly over you products variable.
>>> print("[+] Number of results: {}".format(len(products)))
[+] Number of results: 990
Consider using the format function when building your string. You can use PyFormat website as reference.

Related

How do I solve a two-sum problem with multiple solutions?

So essentially it is a simple two sum problem but there are multiple solutions. At the end I would like to return all pairs that sum up to the target within a given list and then tally the total number of pairs at the end and return that as well. Currently can only seem to return 1 pair of numbers.
So far my solution has to been to try and implement a function that counts the amount of additions done, and while that number is less than the total length of the list the code would continue to iterate. This did not prove effective as it would still not take into account other solutions. Any help would be greatly appreciated
I took your code and did a couple of tweaks to where summations were being tested and how the data was being stored. Following is your tweaked code.
def suminlist(mylist,target):
sumlist = []
count = 0
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i] + mylist[x]
if sum == target:
count += 1
worklist = []
worklist.append(mylist[i])
worklist.append(mylist[x])
sumlist.append(worklist)
return count, sumlist
list = [0, 5, 4, -6, 2, 7, 13, 3, 1]
print(suminlist(list,4))
Things to point out.
The sumlist variable is defined as a list with no initial values.
When a summation of two values in the passed list equate to the test value, they are placed into a new interim list and then that list is appended to the sumlist list along with incrementing the count value.
Once all list combinations are identified, the count value and sumlist are returned to the calling statement.
Following was the test output at the terminal for your list.
#Dev:~/Python_Programs/SumList$ python3 SumList.py
(2, [[0, 4], [3, 1]])
To split the count value out from the list, you might consider splitting the returned data as noted in the following reference Returning Multiple Values.
Give that a try to see if it meets the spirit of your project.
You can use the itertools module for this job.
my_list = [1, 2, 3, 4]
target = 3
out = [x for x in itertools.combinations(my_list, r=2) if sum(x) == target]
print(out)
>>> [(0, 3), (1, 2)]
If you feel like using a python standard library import is cheating, the the official documentation linked above showcases example code for a "low level" python implementation.
Issue:
The issue for returning one set of possible several sets remains in the first return line (return sumlist). Based on the code, the function will automatically ends the function as the first set of value that their sum is the same as the target value. Therefore, we need to adjust it.
Adjustment:
I add a list(finallist[]) at the begining of the function for collecting all the applicable sets that can sum up to the target value. Then, I add a list(list[]) right after the if statement (*since I create an empty list(list[]) right after the if statement, when any sum of two values fulfills the target value, the function will empty the list again to store the new set of two values and append to the finallist[] again). Hence, as long as a set of two numbers can sum up to the target value, we can append them to the list(list[]). Accordingly, I add two more lines of code to append two values into the list(list[]). At the end, I append this list(list[]) to finallist[]. Also, I move the return statement to the final line and adjust the spacing. After this adjustment, the function will not end right after discovering the first possible set of values. Instead, the function will iterate repeatedly until getting all sets of the values and storing in the finalist[].
Originally, the function puts the return statement (return -1) at the end of the function for the situation that none of the sets can sum up to the target value. However, after the previous adjustment, the original return statement (return -1) will not have the opportunity to function as everything will end in the previous return line (return finallist). Therefore, I change it to the else part in the if statement (*meaning: when none of the sum of two values adds up to the target value, we will return 'No two values in the list can add up to the target value.')
Changes in Function:
def suminlist(mylist,target):
# count = 0 # delete
# while count < len(mylist): # delete
finallist=[] # add
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i]+mylist[x]
# count = count + 1 # delete
if sum == target:
# sumlist = mylist[i],mylist[x] # delete
# return sumlist # delete
list=[] # add
list.append(mylist[i]) # add
list.append(mylist[x]) # add
finallist.append(list) # add
else: # add
return 'No two values in the list can add up to the target value.' # add
return finallist # add
# return -1 # delete
Final Version:
def suminlist(mylist,target):
finallist=[]
for i in range(len(mylist)):
for x in range(i+1,len(mylist)):
sum = mylist[i]+mylist[x]
if sum == target:
list=[]
list.append(mylist[i])
list.append(mylist[x])
finallist.append(list)
else:
return 'No two values in the list can add up to the target value.'
return finallist
Test Code and Output:
list = [0, 5, 4, -6, 2, 7, 13, 3, 1]
print(suminlist(list,100))
# Output: No two values in the list can add up to the target value.
print(suminlist(list,4))
# Output: [[0, 4], [3, 1]]

How to append to a list two numbers from within the list that add up to a number in the list?

First, I want to find the highest number in the list which is the second number in the list, then split it in two parts. The first part contains the 2nd highest number, while the second part contains the number from the list that sums to the highest number. Then, return the list
eg: input: [4,9,6,3,2], expected output:[4,6,3,6,3,2] 6+3 sums to 9 which is the highest number in the list
Please code it without itertools.
python
def length(s):
val=max(s)
s.remove(val)
for j in s:
if j + j == val:
s.append(j)
s.append(j)
return s
Here's what I have but it doesn't return what the description states.
Any help would be appreciated as I spent DAYS on this.
Thanks,
The main issue in your code seems to be that you are editing the list s whilst iterating through it, which can cause issues with the compiler and is generally just something you want to avoid doing in programming. A solution to this could be iterating through a copy of the original list.
The second problem is that your program doesn't actually find the second biggest value in the list, just a value which doubles to give you the biggest value.
The final problem (which I unfortunately only noticed after uploading what I thought was a solution) is that the split values are appended to the end of the list rather than to the position where originally the largest value was.
Hopefully this helps:
def length(array):
val = max(array)
idx = array.index(val) # gets the position of the highest value in the array (val)
array.remove(val)
for i in array.copy(): # creates a copy of the original list which we can iterate through without causing buggy behaviour
if max(array) + i == val:
array = array[:idx] + [max(array), i] + array[idx:]
# Redefines the list by placing inside of it: all values in the list upto the previous highest values, the 2 values we got from splitting the highest value, and all values which previously went after the highest value.
return array
This will return None if there is no value which can be added to the second highest value to get the highest value in the given array.
Input:
print(length([1,2,3,4,5]))
print(length([4,8,4,3,2]))
print(length([11,17,3,2,20]))
print(length([11,17,3,2,21]))
Output:
[1, 2, 3, 4, 4, 1]
[4, 4, 4, 4, 3, 2]
[11, 17, 3, 2, 17, 3]
None
Here are the docs on list slicing (which are impossible to understand) and a handy tutorial.
when you say "The first part contains the 2nd highest number" does that mean second highest number from the list or the larger of the two numbers that add up the largest number from list?
Here I assume you just wanted the larger of the two numbers that add up to the largest number to come first.
def length(s:list):
#start by finding the largest value and it's position in the list:
largest_pos = 0
for i in range(len(s)):
if s[i] > s[largest_pos]:
largest_pos = i
# find two numbers that add up to the largest number in the s
for trail in range(len(s)):
for lead in range(trail, len(s)):
if (s[trail] + s[lead]) == s[largest_pos]:
if s[trail] > s[lead]:
s[largest_pos] = s[trail]
s.insert(largest_pos +1, s[lead])
else:
s[largest_pos] = s[lead]
s.insert(largest_pos + 1, s[trail])
return s
# if no two numbers add up to the largest number. return s
return s
Since you are limited to 2 numbers, a simple nested loop works.
def length(s):
val = max(s)
idx = s.index(val)
s.remove(val)
for i in range(len(s) - 1):
for j in range(i + 1, len(s)):
if s[i] + s[j] == val:
s = s[:idx] + [s[i], s[j]] + s[idx:]
return s
print(length([4,9,6,3,2]))
Output:
[4, 6, 3, 6, 3, 2]
I used deque library
first to find the highest element or elements then remove all of them and replace them with second high value and rest like : 9 replace with 6 and 3 in example:
from collections import deque
l = [4, 9, 6, 3, 2]
a = deque(l)
e = a.copy()
s = max(a)
while s in a:
a.remove(s) # remove all highest elements
s2 = max(a) # find second high value
c = s - s2
for i in l:
if i == s:
w = e.index(i) # find index of high values
e.remove(max(e))
e.insert(w, s2)
e.insert(w+1, c)
print(list(e))

How to return stuff from the dictionary and multiply them all?

So I'm trying to multiply every single number that is assigned to each variable in dictionary output and I created a function totalcalories(inputlst) to find it.
So what I'm trying to do is to define a function totalcalories(inputlst) that will return the total number of calories consumed based on every meal you eat.
The calories will be stored in a dictionary like this...
inputlst = {"Cabbage":"4,2,0", "Carrot":"9,1,5", "Fatty Pork":"431,1,5"}
where the first number will be multiplied by 5, the second will be multiplied by 5 and the third one will be multiplied by 9.
so for instance if Cabbage is called, (its numbers are (4,2,0)), the output should return ((4 * 5)+(2 * 5)+(0 * 9)), which is 30.
I tried to do it like this, which clearly doesn't work...
def totalcalories(inputlist):
output = {inputlist}
g= []
for x in output:
g.append(x)
return g
print(totalcalories(["Cabbage"]))
I'm really new to this, so please try to use dictionaries and simple beginner programming tricks to help me out, Thank you:)
You could use something like this:
sum([x*y for x, y in zip(map(int, inputlst["Cabbage"].split(",")),[5,5,9])])
Essentially, after having parsed the list of inputs into ints, you get their respective multipliers side-by-side and using a list comprehension you multiply them.
The function would be:
def calc(name):
return sum([x*y for x, y in zip(map(int, inputlst[name].split(",")),[5,5,9])])
Your code attempt currently does none of the things you want it to do, so it may be best to start from scratch.
Firstly, you will want a function that will take an inputted food (as a string), and your dictionary inputlst, so we can begin with the below:
def totalcalories(food, inputlst):
#calculate calories
Firstly, you're going to need to be able to acess the values associated with your food key in your dictionary. You can do this as below:
inputlst['Cabbage']
Which returns:
'4,2,0'
Your dictionary values are all strings of numbers, which makes things more complicated. It will be easier to use those numbers if you could have them as lists e.g. [4, 2, 0], but we can change the string to a list and remove ',' like below:
values = list(inputlst[food])
values = [x for x in values if x != ',']
So now you have a list of the values ready to be used, so now its a case of multiplying each value by the values you specified above (5, 5 and 9). It might be useful to add these as variables into your function if they are likely to change, but for now I'm going to write it as below:
output = (values[0] * 5) + (values[1] * 5) + (values[2] * 9)
Then you will need to add return output to the end of your function. Hopefully that's enough information for you to be able to put together your function now.
I'm not sure if you have control over your input list or not. But if you do, try converting it to a list of integers instead of a comma separated string. Why? It requires a extra step to convert it to integers for the multiply action.
So turn it into this:
inputlst = {"Cabbage":[4, 2, 0], "Carrot":[9, 1, 5], "Fatty Pork":[431, 1, 5]}
If you're unable to to this directly, you can easily convert your input into this, using map:
inputlst = {"Cabbage":"4,2,0", "Carrot":"9,1,5", "Fatty Pork":"431,1,5"}
# Loop over all key and value in your dict.
for key, value in inputlst.items():
# Split string into the separate numbers.
new_value = value.split(',')
# Convert them into integers using ma[.
# map returns a map object, convert it into a list.
inputlst[key] = list(map(int, new_value))
print(inputlst) # {'Cabbage': [4, 2, 0], 'Carrot': [9, 1, 5], 'Fatty Pork': [431, 1, 5]}
Then in your code, you don't need to do any conversion of the data. Making it easier for yourself and keeps it simple (KISS approach):
# Define a constant with our multipliers.
MULTIPLIERS = [5, 5, 9]
def totalcalories(list_of_integers):
total = 0
# Loop over the integers and keep track of the index of the loop.
for i, integer_value in enumerate(list_of_integers):
# Fetch the multiplier we want for this index.
multiplier = MULTIPLIERS[i]
# Apply multiply and add it to the total.
total += (integer_value * multiplier)
return total
Which we can then easily call in a for loop:
>>> for key, value in inputlst.items():
>>> print(key, totalcalories(value))
Cabbage 30
Carrot 95
Fatty Pork 2205
Or of course just with the value you want:
>>> totalcalories(inputlst['Cabbage'])
30

How to exclude the zeros from this mean function?

I am calculating the mean of a list and making it so that the function also excludes the zeros from the list (because division by zero is impossible).
I tried several things, here is my most successful but it calculates the sum instead.
I made a working function, but I have no idea how to exclude the zeros.
Here is what I tried:
list_value = [5, 3, 8, 0, 4, 5, 1, 0, 14, 10]
'''
test code
'''
mean_out = mean(list_value)
print (mean_out) #---> Prints 55.0
This is the function that works, but doesn't exclude the zeros from the list:
def mean(list_value):
sum = 0
mean_out = len(list_value)/sum
return mean_out
The question is: How do I exclude the zeros from this mean function without using list comprehensions?
you're doing it right. you just need to comment out one line. -
list_value = [5, 3, 8, 0, 4, 5, 1, 0, 14, 10]
def mean(list_value):
sum = 0
for i in list_value:
if i != 0:
print(i)
sum += 1 / i
# list_value.append(i)
return len(list_value)/sum
mean_out = mean(list_value)
print (mean_out)
list_value.append(i) - Here you're appending the value back to the original list and that's why the loop never ends.
Try something like this.
list_value_without_zero = [x for x in list_value if x != 0]
Your problem with the first one is that you're calculating sum of non-zero values but using length of all. Just calculate length of non-zero values using count and you'll be fine. So instead of "len(list_value)" use count and do count+=1 if i !=0
Without list comprehension, to remove all the 0's from your list you can do:
list_value_without_zero = list_value.copy()
while 0 in list_value_without_zero:
list_value_without_zero.remove(0)

Python - Looping through a string pulling 1 character at a time and then 2

Problem:
I have a string of numbers, lets call it strNumbers. I need to go through this string, character by character doing calculations on each number up until a certain point. At that point, I need to start pulling two of the numbers at a time and doing calculations on those two numbers. Here's what I have come up with thus far, as you can see I have figured out how to iterate through the loop pulling single characters no problem. I also understand that I need a counter to determine exactly when I need to start pulling two characters at a time, but now what? Any help is appreciated, thank you.
for i in strNumbers:
intNumber = int (i)
**do math on intNumber*
**print result**
count = count +1
if count == 5:
??
Edit:
I've decided to use two separate loops to accomplish this task, I've encountered another issue however. The following code throws a, TypeError: Can't convert 'int' object to str implicitly at line, number = int(strTail[i:i+2])
for i in strTail:
number = int(strTail[i:i+2])
intRooted = int( math.sqrt(number))
strDecoded += str(intRooted)
Logically this seems like exactly what I want to do, I put to pull the number at position 'i' and the number one position ahead of i. What am I missing here?
You can treat the string as an array accessing each character individually (or two at a time). So once you reach your designated amount you can set a flag that will tell your loop to start taking two characters at a time.
i=0
offset = 1
while i <len(str_numbers):
if offset>1:
int_number = int(str_numbers[i:i+offset])
else:
int_number = int(str_numbers[i])
if i==5:
offset=2
i+=offset
EDIT:
I just thought of a less confusing way of doing this:
offset=1
i=0
while i<len(str_numbers):
if i==5:
offset=2
int_number = int(str_numbers[i:i+offset])
i+=offset
If you already know the number of single characters you want, then you could make two loops:
for s in strNumbers[:count]:
do_something
indices = range(len(strNumbers))
for i in indices[count::2]:
s = strNumbers[i:i+2]
do_something_else
or
for (s1, s2) in zip(strNumbers[count::2], srtNumbers[count+1::2]):
s = s1+s2
do_something_else
>>> my_nums = [1,2,3,4,5,6,7,8,9]
>>> dbl_nums = [[my_nums[i],my_nums[i+1]] for i in range(5,len(my_nums),2)] #double up numbers with index >= 5
>>> sngl_nums = map(lambda x:x*2,my_nums[:5]) #perform some math on single numbers for index < 5
>>> dbl_nums = map(lambda x:x[0]+x[1],dbl_nums) # do some math on 2 nums
>>> print dbl_nums # (6+7 , 8+9 )
[13, 17]
>>> print sngl_nums #(2*1,2*2,2*3,2*4,2*5)
[2, 4, 6, 8, 10]
>>> print sngl_nums+dbl_nums #combined back into one list
[2, 4, 6, 8, 10, 13, 17]
to convert a string of numbers to a list do
my_nums = map(int,num_str)
>>> map(int,"123")
[1, 2, 3]
There's some code we can use in a related question, "How do you split a list into evenly sized chunks in Python?". First split your string into a single-digit section and double-digit section, and chunk as necessary.
def chunks(l, n):
return [l[i:i+n] for i in range(0, len(l), n)]
strNumbers = "123456789012345"
single_part = chunks(strNumbers[:5], 1)
double_part = chunks(strNumbers[5:], 2)
string_numbers = single_part + double_part
numbers = [int(x) for x in string_numbers]
print numbers
#result: [1, 2, 3, 4, 5, 67, 89, 1, 23, 45]

Categories

Resources