problem with dictionaries inserted inside a list - python-3.x

I've done a lot of research but I just can't understand it. I'm trying to create a little program that returns all the currencies within a dictionary and then puts them in a list, but when I print it out I get this
l_report = []
dict_report = {}
def maximum_volume():
global dict_report
list_volume = [] #LIST CONTAINING CURRENCY VOLUMES
for elements in currencies:
list_volume.append(elements['quote']['USD']['volume_24h'])
for elements in currencies:
if max(list_volume) == elements['quote']['USD']['volume_24h']:
dict_report ={
'max_volume' : elements['name']
}
l_report.append(dict_report)
def top10():
global dict_report
list_top = [] #LIST CONTAINING THE VALUES OF CURRENCIES WITH A POSITIVE INCREMENT
for elements in currencies:
if elements['quote']['USD']['percent_change_24h'] > 0:
list_top.append(elements['quote']['USD']['percent_change_24h'])
top10_sorted = sorted(list_top, key=lambda x: float(x), reverse=True)
for num in top10_sorted[:10]:
for elements in currencies:
if num == elements['quote']['USD']['percent_change_24h']:
dict_report={
'name' : elements['name'],
'percent': num
}
l_report.append(dict_report)
maximum_volume()
top10()
for k in l_report:
print(k['name'])
KeyError: 'name'

Related

Data Structure Option

I'm wondering what appropriate data structure I'm going to use to store information about chemical elements that I have in a text file. My program should
read and process input from the user. If the user enters an integer then it program
should display the symbol and name of the element with the number of protons
entered. If the user enters a string then my program should display the number
of protons for the element with that name or symbol.
The text file is formatted as below
# element.txt
1,H,Hydrogen
2,He,Helium
3,Li,Lithium
4,Be,Beryllium
...
I thought of dictionary but figured that mapping a string to a list can be tricky as my program would respond based on whether the user provides an integer or a string.
You shouldn't be worried about the "performance" of looking for an element:
There are no more than 200 elements, which is a small number for a computer;
Since the program interacts with a human user, the human will be orders of magnitude slower than the computer anyway.
Option 1: pandas.DataFrame
Hence I suggest a simple pandas DataFrame:
import pandas as pd
df = pd.read_csv('element.txt')
df.columns = ['Number', 'Symbol', 'Name']
def get_column_and_key(s):
s = s.strip()
try:
k = int(s)
return 'Number', k
except ValueError:
if len(s) <= 2:
return 'Symbol', s
else:
return 'Name', s
def find_element(s):
column, key = get_column_and_key(s)
return df[df[column] == key]
def play():
keep_going = True
while keep_going:
s = input('>>>> ')
if s[0] == 'q':
keep_going = False
else:
print(find_element(s))
if __name__ == '__main__':
play()
See also:
Finding elements in a pandas dataframe
Option 2: three redundant dicts
One of python's most used data structures is dict. Here we have three different possible keys, so we'll use three dict.
import csv
with open('element.txt', 'r') as f:
data = csv.reader(f)
elements_by_num = {}
elements_by_symbol = {}
elements_by_name = {}
for row in data:
num, symbol, name = int(row[0]), row[1], row[2]
elements_by_num[num] = num, symbol, name
elements_by_symbol[symbol] = num, symbol, name
elements_by_name[name] = num, symbol, name
def get_dict_and_key(s):
s = s.strip()
try:
k = int(s)
return elements_by_num, k
except ValueError:
if len(s) <= 2:
return elements_by_symbol, s
else:
return elements_by_name, s
def find_element(s):
d, key = get_dict_and_key(s)
return d[key]
def play():
keep_going = True
while keep_going:
s = input('>>>> ')
if s[0] == 'q':
keep_going = False
else:
print(find_element(s))
if __name__ == '__main__':
play()
You are right that it is tricky. However, I suggest you just make three dictionaries. You certainly can just store the data in a 2d list, but that'd be way harder to make and access than using three dicts. If you desire, you can join the three dicts into one. I personally wouldn't, but the final choice is always up to you.
weight = {1: ("H", "Hydrogen"), 2: ...}
symbol = {"H": (1, "Hydrogen"), "He": ...}
name = {"Hydrogen": (1, "H"), "Helium": ...}
If you want to get into databases and some QLs, I suggest looking into sqlite3. It's a classic, thus it's well documented.

Improve the time efficiency of the anagram string function

How can I improve the time efficiency of my algorithm to solve the following problem?
Problem:
Write a function that takes in a dictionary and query, two string arrays.
It should return an array of integers where each element i contains the number
of anagrams of the query[i] that exists in the dictionary. An anagram of a string is
another string with the same characters in the same frequency, in any order.
Example: "bca", "abc", "cba", "cab" are all anagram of "abc".
Current Solution
from collections import defaultdict
def IsAnagram(word):
# a list of 26 elements, each represents the number of occurrence of every english letter in the word
lst = [0] * 26
for c in word:
lst[ord(c) - 97] += 1
return lst
def anagram_string(query, dictionary):
d = defaultdict(int)
res = []
for w_1 in query:
# if the anagram of w_1 was counted before
if w_1 in d:
res.append(d[w_1])
else:
# define num of anagram for the query in dictionary
num_anagram = 0
# loop through all words of the dictionary
for w_2 in dictionary:
if len(w_1) != len(w_2):
continue
# add 1 to num of anagrams in case all letters of word_1 are the same as in word_2.
num_anagram += IsAnagram(w_1) == IsAnagram(w_2)
res.append(num_anagram)
# record the word with its number of anagrams in the dictionary
d[w_1] = num_anagram
return res
The above code has a Time Complexity of O(n*m) where n is the number of words in the query array and m is the number of words in dictionary array. Although it works fine for a small length array, it takes forever to compute the out array for a list of length 5000+. So, how can I improve it or maybe if someone has a different idea?
Here is my solution in Javascript
const dictionary = ['hack', 'rank', 'khac', 'ackh', 'kran', 'rankhacker', 'a', 'ab', 'ba', 'stairs', 'raits']
const query = ['a', 'nark', 'bs', 'hack', 'stairs']
function evaluate (dictionary, query) {
const finalResult = query.reduce((map, obj) => {
map[obj.split('').sort().join('')] = 0
return map
}, {})
dictionary.forEach(item => {
const stringEvaluate = item.split('').sort().join('')
if (finalResult.hasOwnProperty(stringEvaluate)) {
finalResult[stringEvaluate]++
}
})
return Object.values(finalResult)
}
console.log(evaluate(dictionary, query))
Solution in Python returning count of anagram in sequence which was found in dictionary list.
dictionary = ['hack', 'rank', 'khac', 'ackh', 'kran', 'rankhacker', 'a', 'ab', 'ba', 'stairs', 'raits']
query = ['a', 'nark', 'bs', 'hack', 'stairs']
myList=[sorted(element) for element in dictionary]
def anagram_string(query, dictionary):
resList=[]
for element in query:
count = myList.count(sorted(element))
resList.append(count)
return resList
print(anagram_string(query,dictionary))

Grouping categorical variable in dynamic dataframe in pandas

I have categorical variables based on states.
I want to create a dynamic dataframe with same name and data of filtered state only.
Like for DataAL, we will have all data of AL states only.
Code 1:
l = []
for i in a:
print(i)
l[i] = df4[df4["Provider State"].str.contains(i)]
l[i] = pd.DataFrame(l[i])
l[i].head()
TypeError: list indices must be integers or slices, not str
Code 2:
l = []
for i in range(len(a)):
print(i)
l[i] = df4[df4["Provider State"].str.contains(a[i])]
l[i] = pd.DataFrame(l[i])
l[i].head()
IndexError: list assignment index out of range

Python 3, remove duplicate of tuples in other lists of lists

Hi im looking for a way to remove duplicate of tuples from one list when compared to tuples in others different lists and/or lists of lists of tuples.
Example :
possible_cell = [(7,7),(3,3),(4,4),(5,5)]
wrong_path = [(1,1),(1,2),[(3,3)]]
current_path = [(4,4),[(5,5)]]
this_path = [(6,6)]
wanted :
new_possible_cell = [2-tuple for 2-tuple in possible_cell if 2-tuple not in wrong_path and 2-tuple not in current_path etc....]
expected return :
new_possible_cell = [(7,7)]
You're close, just flatten the list first.
possible_cell = [(7,7),(3,3),(4,4),(5,5)]
wrong_path = [(1,1),(1,2),[(3,3)]]
current_path = [(4,4),[(5,5)]]
this_path = [(6,6)]
def flatten(L):
for x in L:
if type(x) == list:
yield from flatten(x)
else:
yield x
new_possible_cell = [x for x in possible_cell if x not in flatten(wrong_path+current_path+this_path)]
print(new_possible_cell)
output:
[(7, 7)]
If your lists are large, use set(flatten(...)) for better speed.

Was solving a hacker problem and some test cases didnt pass

Given the names and grades for each student in a Physics class of students, store them in a nested list and print the name(s) of any student(s) having the second lowest grade.
Note: If there are multiple students with the same grade, order their names alphabetically and print each name on a new line.
Input Format
The first line contains an integer, , the number of students.
The subsequent lines describe each student over lines; the first line contains a student's name, and the second line contains their grade.
Constraints
There will always be one or more students having the second lowest grade.
Output Format
Print the name(s) of any student(s) having the second lowest grade in Physics; if there are multiple students, order their names alphabetically and print each one on a new line.
This is my code:
list = []
for _ in range(int(input())):
name = input()
score = float(input())
new = [name, score]
list.append(new)
def snd_highest(val):
return val[1]
list.sort(key = snd_highest)
list.sort()
value = list[1]
grade = value[1]
for a,b in list:
if b == grade:
print (a)
This is the test case:
4
Rachel
-50
Mawer
-50
Sheen
-50
Shaheen
51
And the expected output is Shaheen but i got the other 3.
Please explain.
To find the second lowest value, you have actually just sorted your list in ascending order and just taken the second value in the list by using the below code
value = list[1]
grade = value[1]
Imagine this is your list after sorting:
[['Sheen', 50.0], ['mawer', 50.0], ['rachel', 50.0], ['shaheen', 51.0]]
According to value = list[1], the program chooses "value = ['mawer', 50.0]".
Then the rest of your program takes the grade from this value and outputs the corresponding name, that's why this isn't working as per what you need, you need to write logic to find the lowest value and then find the second lowest, this current program just assumes the lowest value is in the second position in the list.
Try doing this
if __name__ == '__main__':
students = []
for _ in range(int(input())):
name = input()
score = float(input())
new = [name, score]
students.append(new)
def removeMinimum(oldlist):
oldlist = sorted(oldlist, key=lambda x: x[1])
min_ = min(students, key=lambda x: x[1])
newlist = []
for a in range(0, len(oldlist)):
if min_[1] != oldlist[a][1]:
newlist.append(oldlist[a])
return newlist
students = removeMinimum(students);
# find the second minimum value
min_ = min(students, key=lambda x: x[1])
# sort alphabetic order
students = sorted(students, key=lambda x: x[0])
for a in range(0, len(students)):
if min_[1] == students[a][1]:
print(students[a][0])
I hope this may help you to pass all your test cases. Thank you.
# These functions will be used for sorting
def getSecond(ele):
return ele[1]
def getFirst(ele):
return ele[0]
studendList = []
sortedList = []
secondLowestStudents = []
# Reading input from STDIN and saving in nested list [["stud1": <score>], ["stud2", <score>]]
for _ in range(int(input())):
name = input()
score = float(input())
studendList.append([name, score])
# sort the list by score and save it in a new list studendList (remove the duplicate score as well - see, if x[1] not in sortedList)
studendList.sort(key=getSecond)
[sortedList.append(x[1]) for x in studendList if x[1] not in sortedList]
# Get the second lowest grade
secondLowest = sortedList[1]
# Now sort the origin list by the name fetch the student list having the secondLowest grade
studendList.sort(key=getFirst)
[secondLowestStudents.append(x[0]) for x in studendList if x[1] == secondLowest]
# Print the student's name having second-lowest grade
for st in secondLowestStudents:
print(st)

Resources