I am trying to parse a JSON page in Python, it is contained in a variable reddit_front.
I am trying to get the sum of all "ups" in this page. I do have the right answer which is the following:
def total_ups():
j=json.loads(reddit_front)
return sum(c["data"]["ups"] for c in j["data"]["children"])
However why does the following loop give me only 1 item and not iterate over?
def total_ups():
j=json.loads(reddit_front)
for c in j["data"]["children"]:
i = c["data"]["ups"]
a = +i
return a
PS: ok, all good points and thx for the negative reputations points, it's fair call I wasn't precise in my question.
return will stop the loop, try appending it to a list then you can join it or whatever you need to so you can get the data.
Example:
def total_ups():
a = list()
j=json.loads(reddit_front)
for c in j["data"]["children"]:
i = c["data"]["ups"]
a.append(+i)
return a
print(total_ups()) # returns list
print(", ".join(total_ups)) # returns a string separated by commas
Maybe...
def total_ups():
children = json.loads(reddit_front)["data"]["children"]
return sum(c["data"]["ups"] for c in children)
Related
I have this string delimited by commas.
'1.0,5.0,6.0,7.0,8.0,9.0'
def var():
for i in listnumbers:
return i +'.0'
When I do
var()
I only get
1.0
How do i get the result to include all the numbers in a loop?
1.0,5.0,6.0,7.0,8.0,9.0
def myfun(mycsv):
return [i+'.0' for i in mycsv.split(',')]
print(myfun('1.0,5.0,6.0,7.0,8.0,9.0'))
#['1.0.0', '5.0.0', '6.0.0', '7.0.0', '8.0.0', '9.0.0']
If you want a string, then just use join:
print(','.join(myfun('1.0,5.0,6.0,7.0,8.0,9.0')))
Or change the function to return a string;
return ','.join([i+'.0' for i in mycsv.split(',')])
You are returning inside the for loop, before the cycle is completed.
If I understood correctly your question, it looks like what you're looking for is list comprehension.
If your input is a list:
def var(l):
return [i + '.0' for i in l]
If your input is a string, like it seems from your description, you have to split it first:
def var(l):
return [i + '.0' for i in l.split(',')]
This is equivalent to mapping in other languages.
You can divide your string in a list using string.split(',') the you iterate over the freshly created list and print each element. A the code can be arranged like this:
for s in string.split(','):
print(s+'.0')
Let's say I know beforehand that the string
"key1:key2[]:key3[]:key4" should map to "newKey1[]:newKey2[]:newKey3"
then given "key1:key2[2]:key3[3]:key4",
my method should return "newKey1[2]:newKey2[3]:newKey3"
(the order of numbers within the square brackets should stay, like in the above example)
My solution looks like this:
predefined_mapping = {"key1:key2[]:key3[]:key4": "newKey1[]:newKey2[]:newKey3"}
def transform(parent_key, parent_key_with_index):
indexes_in_parent_key = re.findall(r'\[(.*?)\]', parent_key_with_index)
target_list = predefined_mapping[parent_key].split(":")
t = []
i = 0
for elem in target_list:
try:
sub_result = re.subn(r'\[(.*?)\]', '[{}]'.format(indexes_in_parent_key[i]), elem)
if sub_result[1] > 0:
i += 1
new_elem = sub_result[0]
except IndexError as e:
new_elem = elem
t.append(new_elem)
print ":".join(t)
transform("key1:key2[]:key3[]:key4", "key1:key2[2]:key3[3]:key4")
prints newKey1[2]:newKey2[3]:newKey3 as the result.
Can someone suggest a better and elegant solution (around the usage of regex especially)?
Thanks!
You can do it a bit more elegantly by simply splitting the mapped structure on [], then interspersing the indexes from the actual data and, finally, joining everything together:
import itertools
# split the map immediately on [] so that you don't have to split each time on transform
predefined_mapping = {"key1:key2[]:key3[]:key4": "newKey1[]:newKey2[]:newKey3".split("[]")}
def transform(key, source):
mapping = predefined_mapping.get(key, None)
if not mapping: # no mapping for this key found, return unaltered
return source
indexes = re.findall(r'\[.*?\]', source) # get individual indexes
return "".join(i for e in itertools.izip_longest(mapping, indexes) for i in e if i)
print(transform("key1:key2[]:key3[]:key4", "key1:key2[2]:key3[3]:key4"))
# newKey1[2]:newKey2[3]:newKey3
NOTE: On Python 3 use itertools.zip_longest() instead.
I still think you're over-engineering this and that there is probably a much more elegant and far less error-prone approach to the whole problem. I'd advise stepping back and looking at the bigger picture instead of hammering out this particular solution just because it seems to be addressing the immediate need.
Suppose I have the following function:
def function3(start, end):
"""Read MO information."""
config_found = False
var = []
for line in v['molecular orbital primitive coefficients']:
if line.strip() == end:
config_found = False
elif config_found:
i = line.rstrip()
var.append(i)
elif line.strip() == start:
config_found = True
var1 = [elem.strip() for elem in var]
var2 = var1[1:-1]
var3 = np.array([line.split() for line in var2])
var3 = np.asarray([list(map(float, item)) for item in var3])
return var3
And suppose I store its output in variables like so:
monumber1=function3('1','2')
monumber2=function3('2','3')
monumber3=function3('3','4')
etc.
Is there a way for me to execute this function a set number of times and store the output in a set number of variables without manually setting the variable name and function arguments every time? Maybe using a for loop? This is my attempt, but I'm struggling to make it functional:
for i in xrange(70):
monumber[x] = function3([i],[i+1])
Thank you!
The problem is your use of square brackets. Here is code that should work:
monumber = [] # make it an empty list
for i in xrange(70):
monumber.append(function3(str(i),str(i+1))) # you had string integers, so cast
For the more Pythonic one-liner, you can use a list comprehension:
monumber = [function3(str(i),str(i+1)) for i in xrange(70)]
Now that the monumber variable has been created, I can access the element at any given index i using the syntax monumber[i]. Some examples:
first = monumber[0] # gets the first element of monumber
last = monumber[-1] # gets the last index of monumber
for i in xrange(10,20): # starts at i = 10 and ends at i = 19
print(monumber[i]) # print the i-th element of monumber
You've almost got it. Except you should use i on the left hand side, too:
monumber[i] = function3([i],[i+1])
Now, this is the basic idea, but the code will only work if monumber is already a list with enough elements, otherwise an IndexError will occur.
Instead of creating a list and filling it with placeholders in advance, we can dynamically append new values to it:
monumber = []
for i in xrange(70):
monumber.append(function3([i],[i+1]))
Another problem is that you seem to be confusing different types of arguments that your function works with. In the function body, it looks like start and end are strings, but in your code, you give to lists with one integer each. Without changing the function, you can do:
monumber = []
for i in xrange(70):
monumber.append(function3(str(i),str(i+1)))
If I want to define a function called match_numbers, which would match the area code from one list to the phone number of another list, how should I fix my code? For example:
match_phone(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
would give me
(666)313-2534
(332)123-3332
My code is:
def phone (nlist, nlist1):
results = {}
for x in nlist1:
results.setdefault(x[0:3], [])
results[x[0:3]].append(x)
for x in nlist:
if x in results:
print(results[x])
The problem with this code is, however:
It gives me the outputs in brackets, whereas I want it to print
the output line by line like shown above, and
it won't work with the parantheses in the 2nd list (for example
(666)543-2322 must be converted as 666-543-2322 for the list to
work.
Now, there are better/faster approaches to do what you are trying to do, but let us focus on fixing your code.
The first issue you have is how you are slicing your string. Remember that you start at index 0. So if you do:
x[0:3]
What you are actually getting is something like this from your string:
(12
Instead of your intended:
123
So, knowing that indexes start at 0, what you actually want to do is slice your string as such:
x[1:4]
Finally, your line here:
results[x[0:3]].append(x)
There are two problems here.
First, as mentioned above, you are still trying to slice the wrong parts of your string, so fix that.
Second, since you are trying to make a key value pair, what that above line is actually doing is making a key value pair where the value is a list. I don't think you want to do that. You want to do something like:
{'123': '(123)5556666'}
So, you don't want to use the append in this case. What you want to do is assign the string directly as the value for that key. You can do that as such:
results[x[1:4]] = x
Finally, another problem that was noticed, is in what you are doing here:
results.setdefault(x[1:4], [])
Based on the above explanation on how you want to store a string as your value in your dictionary instead of a list, so you don't need to be doing this. Therefore, you should simply be removing that line, it does not serve any purpose for what you are trying to do. You have already initialized your dictionary as results = {}
When you put it all together, your code will look like this:
def match_phone(nlist, nlist1):
results = {}
for x in nlist1:
results[x[1:4]] = x
for x in nlist:
if x in results:
print(results[x])
match_phone(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
And will provide the following output:
(666)313-2534
(332)123-3332
If all the phone numbers will be in the format (ddd)ddd-dddd you can use
for number in (num for num in nlist1 if num[1:4] in nlist):
print(number)
You could use some better variable names than nlist and nlist1, in my view.
def match_phone(area_codes, numbers):
area_codes = set(area_codes)
for num in numbers:
if num in area_codes:
print num
You could do something like this:
phone_numbers = ['(443)241-1254', '(666)313-2534', '(332)123-3332']
area_codes = ['666', '332']
numbers = filter(lambda number: number[1:4] in area_codes, phone_numbers)
for number in numbers:
print(number)
Another similar way to do this without using a filter could be something like this:
for number in phone_numbers:
if number[1:4] in area_codes:
print(number)
Output in either case would be:
(666)313-2534
(332)123-3332
No one with regex solution! This may be an option too.
import re
def my_formatter(l1,l2):
mydic = {re.match(r'([(])([0-9]+)([)])([0-9]+[-][0-9]+)',i).group(2):re.match(r'([(])([0-9]+)([)])([0-9]+[-][0-9]+)',i).group(4) for i in l2}
for i in l1:
print "({0}){1}".format(str(i),str(mydic.get(i)))
my_formatter(['666', '332'], ['(443)241-1254', '(666)313-2534', '(332)123-3332'])
It prints-
(666)313-2534
(332)123-3332
In web2py I have been trying to break down this list comprehension so I can do what I like with the categories it creates. Any ideas as to what this breaks down to?
def menu_rec(items):
return [(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)) for x in items or []]
In addition the following is what uses it:
response.menu = [(SPAN('Catalog', _class='highlighted'), False, '',
menu_rec(db(db.category).select().as_trees()) )]
So far I've come up with:
def menu_rec(items):
for x in items:
return x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children))
I've got other variations of this but, every variation only gives me back 1(one) category, when compared to the original that gives me all the categories.
Can anyone see where I'm messing this up at? Any and all help is appreciated, thank you.
A list comprehension builds a list by appending:
def menu_rec(items):
result = []
for x in items or []:
url = URL('shop', 'category', args=pretty_url(x.id, x.slug))
menu = menu_rec(x.children) # recursive call
result.append((x.title, None, url, menu))
return result
I've added two local variables to break up the long line somewhat, and to show how it recursively calls itself.
Your version returned directly out of the for loop, during the first iteration, and never built up a list.
You don't want to do return. Instead append to a list and then return the list:
def menu_rec(items):
result = []
for x in items:
result.append(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)))
return result
If you do return, it will return the value after only the first iteration. Instead, keep adding it to a list and then return that list at the end. This will ensure that your result list only gets returned when all the values have been added instead of just return one value.