How to return collection from a function - python

I'm working with collection's namedtuple to return a list of tuple from within a function as such:
def getItems(things_list) -> list:
for i, j in enumerate(things_list):
[*things_id] = things_list[i].id
[*things_title] = things_list[i].title
things_structure = namedtuple('things', ['id', 'title'])
[*things_list] = [
things_structure(things_id, things_title)
]
return things_list
if I run
callGetItems = getItems(list_of_things) # assume list_of_things is a dictionary
print(callGetItems)
it will only print the first index of the return value, as you can see I'm actually expecting the whole dictionary to be printed with their respective id and title.(assume there is at least 3 different Key-value pairs in the dictionary)
P.s. If I print within the function, it prints all the elements stored in the [*things_list] variable as expected but the same cannot be said for iterating over the return value i.e., outside of the function. please help.
to deobfuscate things assume this is the dictionary list_of_things:
list_of_things = [
{"id" : 1,
"title" : "waterbottle",
"description" : "a liquid container"},
{"id": 2,
"title": "lunchbox",
"description": "a food container"}
]
# etc...

Is this what you were going for? Creating a list of named tuples from the original list of dicts?
from collections import namedtuple
list_of_things = [
{"id": 1, "title": "waterbottle", "description": "a liquid container"},
{"id": 2, "title": "lunchbox", "description": "a food container"},
]
def getItems(things_list) -> list:
things_structure = namedtuple("things", ["id", "title"])
return [things_structure(k["id"], k["title"]) for k in things_list]
new_things = getItems(list_of_things)
print(new_things)

Related

Assemble separate sentences connected by dictionary attributes

I have the following list of dictionaries and I'm trying to come up with a single connected sentence based on whether the fact that the dictionary of the child sentences have the "ref" attribute connecting it to the father sentence.
clause_list = [
{"id": "T1", "text": "hi"},
{"id": "T2", "text": "I'm", "ref": "T1"},
{"id": "T3", "text": "Simone", "ref": "T2"},
]
Expected output is
"hi I'm Simone" but avoiding sentences like "hi I'm" or "I'm Simone"
What I tried so far is the following, but no matter how I flip it, the undesired sentences always get printed.
for c in clause_list:
for child in clause_list:
try:
if c["id"] == child["ref"] and "ref" not in c.keys():
print(c["text"], child["text"])
elif c["id"] == child["ref"] and "ref" in c.keys():
for father in clause_list:
if father["id"] == c["ref"] and "ref" not in father.keys():
print(father["text"], c["text"], child["text"])
except KeyError:
pass
probablly is best use a class and not a dict, but you could convert to list of dict to list of classes easy.
This work. Convert the list of dict to list of Clauses. and the clauses has the method search_ref that print the partial text if there are no referenced object, or add the referenced object and continue if there are.
if you have 2 objects i don't know exactly what you want
clause_list = [
{"id": "T1", "text": "hi"},
{"id": "T2", "text": "I'm", "ref": "T1"},
{"id": "T3", "text": "Simone", "ref": "T2"},
]
class Clause:
def __init__(self, id, text, ref:None):
self.id = id
self.text = text
self.ref = ref
def search_ref(self, Clauses, text=''):
parcialText = text + ' ' + self.text
for clause in Clauses:
if clause.ref == self.id:
return clause.search_ref(Clauses, parcialText)
print(parcialText)
Clauses = [Clause(id=c['id'], text=c['text'], ref=c.get('ref')) for c in clause_list]
for c in Clauses:
if c.ref is None:
c.search_ref(Clauses)
So right now you have your data set up as a list of dictionaries. I think it will be more helpful if you set it up as a linked list instead and use a bit of recursion. Maybe something like below. As a note, you'll need something to indicate the start of the sentence (I'm going to use "parent=True"):
clause_list = {
# ID's are the keys
'T1':{'text':"hi ", 'child':'T2','parent':True},
'T2':{'text':"I'm ", 'child':'T3'},
'T3':{'text':"Simone", 'child':None},
}
Then your code can look like this:
# Recursive function
def print_child(child_id, clause_list):
print(clause_list[child_id]['text'])
if 'child' in clause_list[child_id]:
print_child(clause_list[child_id]['child'], clause_list)
# Main function
for id in clause_list:
if 'parent' in clause_list[id]:
print(clause_list[id]['text'])
# Recurse through the parent to find others
if 'child' in clause_list[id]:
print_child(clause_list[id]['child'], clause_list)
Cloud definitely be cleaned up a bit and optimized, but this is the general gist. Hope it helps!
Another solution using a recursion:
clause_list = [
{"id": "T1", "text": "hi"},
{"id": "T2", "text": "I'm", "ref": "T1"},
{"id": "T3", "text": "Simone", "ref": "T2"},
]
inv_dict = {d.get("ref", ""): (d["id"], d["text"]) for d in clause_list}
def get_sentence(inv_dict, key=""):
if key in inv_dict:
id_, text = inv_dict[key]
return [text] + get_sentence(inv_dict, id_)
return []
print(" ".join(get_sentence(inv_dict)))
Prints:
hi I'm Simone

Why is my for loop filling in values into the next json object if it has an empty array?

I'm working with a large number of large json files. I've written the below (extremely un elegant code) in order to generate two dictionaries with which I can create a dataframe to work with. However, in instances where the JSON has values with empty arrays, my code is propagating the last 'valid' values into the subsequent objects with empty arrays. I've tried replacing empty arrays with blanks but that doesn't seem to work either. (I know my code is very bad - still learning so please keep that in mind)
dicts = []
fid = []
x=0
while x < 1:
for i in files:
n=[]
k = []
t = []
op = open(i)
data = op.read()
js = json.loads(data)
items = js['metadata']['items']
#items = json.dumps(items).replace('[]','""')
#items = json.loads(items)
fileid = js['id']
fid.append(fileid)
##Everything after this point is what's throwing me off##
for a in items:
b = json.loads(json.dumps(a, sort_keys =True))
key = b['name']
k.append(key)
val = b['values']
values = []
for c in val:
j=json.dumps(c['value'])
if isinstance(c, list) == False:
continue
values.append(j)
j = ';'.join(values) #<-- For objects with more than one value
t.append(j)
output_dict = dict(zip([key], [j]))
n.append(output_dict)
dicts.append(n)
x = x+1
Here is an example section of the json where I'm observing this behavior:
x = {"metadata": {
"items": [
{
"values": [
{ "attribute1": "attribute", #<-- NOT IMPORTANT
"value": "VALUE 1" #<----VALUE I'M AFTER
},
{"attribute2": "attribute",#<-- NOT IMPORTANT
"value2": "VALUE 2"#<----VALUE I'M AFTER
}
],
"name": "NAME 1" #<--NAME I'M AFTER
},
{
"values": [
{
"value": []#<-- EMPTY ARRAY
}
],
"name": "NAME 2"}
]
}
}
In the above snippet, my ideal output is a list of dictionary pairings that looks like:
[{"NAME 1": "VALUE 1; VALUE 2", "NAME 2": " "...}]
But what I'm getting is:
[{"NAME 1": "VALUE 1; VALUE 2"}, {"NAME 2": "VALUE 1; VALUE 2"}...}]
I've tried deconstructing my work, and can't figure out why. I've re-indented and done a walk through a couple times and I don't understand why it would behave like this. What about the way my loop is constructed is causing this?

Why is this dictionary comprehension for list of dictionaries not returning values?

I am iterating over a list of dictionaries in a list formatted as follows (each dictionary relates to one item of clothing, I have only listed the first:
new_products = [{'{"uniq_id": "1234", "sku": "abcdefgh", "name": "Levis skinny jeans", '
'"list_price": "75.00", "sale_price": "55.00", "category": "womens"}'}]
def find_product(dictionary, uniqid):
if 'uniq_id' in dictionary:
if ['uniq_id'] == uniqid:
return(keys, values in dictionary)
print(find_product(new_products, '1234'))
This is returning
None
The reason for the if statement in there is that not every product has a value for uniq_id so I was getting a key error on an earlier version of my code.
Your dictionary definition is quite unclear.
Assuming that you have given a list of dictionaries of size 1, it should be something like this:
new_products = [{"uniq_id": "1234", "sku": "abcdefgh", "name": "Levis skinny jeans", "list_price": "75.00", "sale_price": "55.00", "category": "womens"}]
def find_product(list_of_dicts, uniqid):
for dictionary in list_of_dicts:
if 'uniq_id' in dictionary:
if dictionary['uniq_id'] == uniqid:
return dictionary
print(find_product(new_products, '1234'))
You are using something like this:
new_products = [{'{ "some" : "stuff" }'}]
This is a list (the outer []) containing a set (the {})
{'{ "some" : "stuff" }'}
Note {1} is a set containing the number 1. Though it uses the curly braces it isn't a dictionary.
Your set contains a string:
'{ "some" : "stuff" }'
If I ask if 'some' is in this, I get True back, but if I ask for this string's keys there are no keys.
Make your new_products a list containing a dictionary (not a set), and don't put the payload in a string:
new_products = [{"uniq_id": "1234",
"sku": "abcdefgh",
"name": "Levis skinny jeans",
"list_price": "75.00",
"sale_price": "55.00",
"category": "womens"}]
Then loop over the dictionaries in the list in your function:
def find_product(dictionary_list, uniqid):
for d in dictionary_list:
if 'uniq_id' in d:
if d['uniq_id'] == uniqid:
return d.keys(), d.values()
return "not found" # or something better
>>> find_product(new_products, '1234')
(dict_keys(['uniq_id', 'sku', 'name', 'list_price', 'sale_price', 'category']), dict_values(['1234', 'abcdefgh', 'Levis skinny jeans', '75.00', '55.00', 'womens']))
>>> find_product(new_products, '12345')
'not found'

How do I extract a list item from nested json in Python?

I have a json object and I'm trying to extract a couple of values from a nested list. Then print them in markup. I'm getting and error - AttributeError: 'list' object has no attribute 'get'
I understand that it's a list and I can't preform a get. I've been searching for the proper method for a few hours now and I'm running out of steam. I'm able to get the Event, but not Value1 and Value2.
This is the json object
{
"resource": {
"data": {
"event": "qwertyuiop",
"eventVersion": "1.05",
"parameters": {
"name": "sometext",
"othername": [
""
],
"thing": {
"something": {
"blah": "whatever"
},
"abc": "123",
"def": {
"xzy": "value"
}
},
"something": [
"else"
]
},
"whatineed": [{
"value1": "text.i.need",
"value2": "text.i.need.also"
}]
}
}
}
And this is my function
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource', {})
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = f'''
h3. Details
*Event:* {some_data.get('event')}
*Value1:* {whatineed_data('value1')}
*Value2:* {whatineed_data('value2')}
'''
From the data structure, whatineed is a list with a single item, which in turn is a dictionary. So, one way to access it would be:
whatineed_list = specific_data.get('whatineed', [])
whatineed_dict = whatineed_list[0]
At this point you can do:
value1 = whatineed_dict.get('value1')
value2 = whatineed_dict.get('value2')
You can change your function to the following:
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource')
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = '''
h3. Details
*Event:* {}
*Value1:* {}
*Value2:* {}
'''.format(some_data.get('data').get('event'),whatineed_data[0]['value1'], whatineed_data[0]['value2'])
Since whatineed_data is a list, you need to index the element first
Python handles json as strings unless they are coming directly from a file. This could be the source for some of your problems. Also this article might help.
Assuming that "whatineed" attribute is really a list, and it's elements are dicts, you can't call whatineed.get asking for Value1 or Value2 as if they are attributes, because it is a list and it don't have attributes.
So, you have two options:
If whatineed list has a single element ever, you can access this element directly and than access the element attributes:
element = whatineed[0]
v1 = element.get('value1', {})
v2 = element.get('value2', {})
Or, if whatineed list can have more items, so, you will need to iterate over this list and access those elements:
for element in whatineed:
v1 = element.get('value1', {})
v2 = element.get('value2', {})
## Do something with values

How to convert list of items into json parent-child hierarchy?

I have some items in a list with points, sub-points and sub-sub points need to pass all of them into json in parent-child hierarchy.
I tried as each point made it to list, if a point consist of point, sub or sub-sub-point all becomes in one list of a point.
my list appears like this:
lst=["1. content","(a) content","(b) ","(i)","(ii"),"(c)","2.","3.","(A)","(B)","4."]
for ptags in soup.findAll('p'):
lst.append(ptags.get_text())
regex = r"^\([a-z]\)\s.*"
regex1=r"^\([\D]+\)\s.*"
j=0
sub = []
for i in lst:
if sub:
match = re.match(regex, i)
match1=re.match(regex1,i)
if match:
sub.append(i)
elif match1:
sub.append(i)
else:
j=j+1
sub = [i]
Notes[str(j)] = sub
else:
if sub:
Notes[str(j)] = sub
sub = [i]
Notes[str(j)] = i
I need the json hierarchy as output in this way :
"1. content",
"(a) content",
"(b) ",
"(i)",
"(ii"),
"(c)",
"2.",
"3.",
"(A)",
"(B)",
"4."
######################################JSON STRUCTURE
[
{
"1. content": [
"(a) content",
{
"(b) ": [
"(i)",
"(ii)"
]
},
"(c)"
]
},
"2.",
{
"3.": [
"(A)",
"(B)"
]
},
"4."
]
If you want to have a similar hierarchy, you should change your data to a dict. Because you did not include enough information in your code, I just add a sample of what your data should look like:
from json import dumps
lst = [{"1. content": ["(a) content", {"(b) ": ["(i)","(ii)"]},"(c)"]},"2.",{"3.": ["(A)","(B)"]},"4."]
Each hierarchy level should be a dictionary. For elements those have no children, you can pass them as a simple list element.
You can get your json string using dumps now:
dumps(lst)

Categories