How can I iterate two list of maps at once? - functional-programming

I have two maps containing a list of maps. How can I filter "customers" map, returning only customers that have a proposal in the proposal list?
%{proposals:
[
%App.Structs.Proposal{customer_id: "5202845", ...other_fields},
%App.Structs.Proposal{customer_id: "9778978", ...other_fields}
]
}
%{customers:
[
%App.Structs.Customer{id: "5202845", ...other_fields},
%App.Structs.Customer{id: "5643635", ...other_fields},
%App.Structs.Customer{id: "9778978", ...other_fields},
%App.Structs.Customer{id: "3423454", ...other_fields}
]
}
What I want:
-> Given the list, I'll run a function that will return the name of this customer.
I've tried two "for", filter by ids then compare the two lists, reduce the customer list based in id... None of them worked.
Any suggestions?

The easiest way would be to use a comprehension (thanks #keroro520 for the formatted input):
proposals = [
%{customer_id: "5202845", other: "foo"},
%{customer_id: "9778978", other: "foo"}
]
customers = [
%{id: "5202845", name: "foo"},
%{id: "5643635", name: "bar"},
%{id: "9778978", name: "baz"},
%{id: "3423454", name: "boo"}
]
for %{customer_id: cid} <- proposals,
cs <- Enum.filter(customers, & &1.id == cid),
do: cs.name
#⇒ ["foo", "baz"]
I have to say, though, that you are doing it wrong in the first place. The lookup is unavoidably done for each proposal’s customer_id, leading to O(N²) efficiency, which is generally bad.
The best approach would be probably to convert proposals to Ecto schema, with customers embedded. The reinvented wheel would look like introducing a Proposal.new/2 method that will both update the struct itself and immediately lookup customers to update the nested customer_names field (the same should be done for Customer struct to update proposals respectively.) Both could live in Agent to maintain their state. Maybe it’s a premature optimization, though.

You could try the code below (However, I think maybe it is better if you change proposals and customers data structure, for example, use map data structure and id as key).
customer_ids = Enum.map(proposals, &Map.get(&1, :customer_id))
customers_id_names = Enum.map(customers, &{Map.get(&1, :id), Map.get(&1, :name)})
|> Enum.into(%{})
Map.take(customers_id_names, customer_ids)
Complete module code: https://gist.github.com/keroro520/61173bda3b1441e8a6be25eb0166c6f8

An easy way is to do exactly as you said: filter "customers" map
First, we shamelessly copy paste some of the hard work on part of #keroro520:
some_map = %{
proposals: [
%{customer_id: "5202845", other: "foo"},
%{customer_id: "9778978", other: "foo"}
],
customers: [
%{id: "5202845", name: "foo"},
%{id: "5643635", name: "bar"},
%{id: "9778978", name: "baz"},
%{id: "3423454", name: "boo"}
]}
Then we start off with singling out the foreign keys from proposals:
proposals = Enum.map(some_map[:proposals], &(&1[:customer_id]))
Then we do a simple filter over customers:
filtered_customers = Enum.filter(some_map[:customers], fn %{id: id} -> Enum.member?(proposals, id) end)
These are all the customers with their full fledged details that have a proposal belonging to them. If you only want their names, then map their names accordingly:
Enum.map(filtered_customers, &(&1[:name]))
And there pops out as your answer:
["foo", "baz"]

Just one other way of doing it, I personally use reduce a lot. (your data structures are also a bit weird and if you're assembling them somewhere you could skip the entire into just by making an "orders" map initially instead of a list - this also doesn't "iterate" two lists at once, but I doubt that's what you want either way)
proposals = %{proposals:
[
%App.Structs.Proposal{customer_id: "5202845", some: "foo"},
%App.Structs.Proposal{customer_id: "9778978", some: "baz"}
]
}
customers = %{customers:
[
%App.Structs.Customer{id: "5202845", name: "one"},
%App.Structs.Customer{id: "5643635", name: "two"},
%App.Structs.Customer{id: "9778978", name: "three"},
%App.Structs.Customer{id: "3423454", name: "four"}
]
}
props = Enum.into(proposals.proposals, %{}, fn(%App.Structs.Proposal{customer_id: ci}) ->
{ci, true} end)
Enum.reduce(customers.customers, [], fn(%App.Structs.Customer{id: id, name: name}, acc) ->
case props[id] do
nil -> acc
_ -> [name | acc]
end) end)

Related

Google Schema.org Math solvers structured data for multiple fields

Trying to setup schema markup for a simple math solver action with two fields. Let's say addition.
1+1=2
Here is Google's doc and example:
{
"#context": "https://schema.org",
"#type": ["MathSolver", "LearningResource"],
"name": "An awesome math solver",
"url": "https://www.mathdomain.com/",
"usageInfo": "https://www.mathdomain.com/privacy",
"inLanguage": "en",
"potentialAction": [{
"#type": "SolveMathAction",
"target": "https://mathdomain.com/solve?q={math_expression_string}",
"mathExpression-input": "required name=math_expression_string",
"eduQuestionType": ["Polynomial Equation","Derivative"]
}],
"learningResourceType": "Math solver"
}
How do we add multiple variables for two numbers?
return {
'#context': 'https://schema.org',
'#type': ['MathSolver', 'LearningResource'],
...
potentialAction: [
{
'#type': 'SolveMathAction',
target: `domain.com/?num1={num1}&num2={num2}`,
'mathExpression-input': 'required name=num1 name=num2',
eduQuestionType: ['addition', 'sum']
},
],
learningResourceType: 'Math solver'
};
Schema.org says about mathExpression (note: mathExpression-input doesnt seem to exist) but does fall under Thing > Intangible EntryPoint
A mathematical expression (e.g. 'x^2-3x=0') that may be solved for > a specific variable, simplified, or transformed. This can take many > formats, e.g. LaTeX, Ascii-Math, or math as you would write with a > keyboard.
But can this be setup for URL params to accept multiple fields within the mathExpression-input instead of a single math expression?

NoSQL Database Structure

For a small app prototype I'm building, I would like to use firestore (firebase) to store some data. I'm wondering if the following is a good way of going about a nosql database.
I have Paths, that belong to Categories. A Path can have courses and comments. I would like users to see the likes a path has, and get categories sorted by the amount of paths inside.
That's why I'm adding the paths_count on the categories table, I will use Cloud Functions to update the counts for the likes and paths on each database update.
categories: [
1: {name: "productivity", paths_count: 10},
2: {name: "cooking", paths_count: 5},
]
paths: [
1: {
name: "Productivity 101",
category_id: 1,
likes_count: 5,
likes: [],
courses: [],
comments: []
}
]
Is this a good start?

Ansible list of dicts - accessing keys after a list filter

Taking this playbook YAML:
---
- hosts: localhost
become: false
vars:
list_of_dicts:
- { key1: "cccc", key2: "dddd" }
- { key1: "aaaa", key2: "bbbb" }
tasks:
- name: debug list
debug:
msg: "{{ list_of_dicts|sort(attribute='key1')|first }}"
How can I access the dict keys as a result of the filter chain? The filter produces a dict that looks like this:
ok: [localhost] => {
"msg": {
"key1": "aaaa",
"key2": "bbbb"
}
}
I just want to access key2 in the filter chain - I pictured something like ...|first.key2 but that infers first is an object which it isn't (and similarly fails for first['key2'])
This is for sure a duplicate, but I can't find corresponding answer. I wish SO had a better search engine.
You can group expressions in Jinja2, like follows:
(list_of_dicts|sort(attribute='key1')|first).key2

structure data for different queries

I am learning firebase and trying to find the best way to structure my data.
Use an example of a simple leave application. Employees can submit and view their leaves. Managers can approve leaves.
Option 1
"leaves": [
{
"employee": "pCIUfttSrXQ1dLPDwH7j9GExCkA2",
"date": "2017-03-01",
"status": "pendingApproval",
},
{
"employee": "YSJCAe4wZdYCplA3e0ejMqzQmEF3",
"date": "2017-01-01",
"status": "approved"
}]
With option 1, filtering will be required in both cases:
When employee lists his leave history (filter by "employee")
When manager lists all the pending leaves (filter by "status=pending")
Option 2
"leaves":
{
"pCIUfttSrXQ1dLPDwH7j9GExCkA2" : [
{
"date": "2017-03-01",
"status": "pendingApproval"
}
],
"YSJCAe4wZdYCplA3e0ejMqzQmEF3" : [
{
"date": "2017-01-01",
"status": "approved"
}
]
}
With option 2, no filtering is required when employee lists his leave history, but filtering is required (and I don't know how) for manager to list pending leaves.
What should be the right way to structure the data? And if it's option 2, how would we filter the pending leaves for all employees?
Use the second option;
For the manager to filter through the pending queries , use:
FIRDatabase.database().reference().child("leaves").queryOrdered(byChild: "status").queryEqual(toValue: "pending").observeSingleEvent(of: .value, with: {(Snapshot) in
print(Snapshot.value!)
// If you have multiple pending request you gotta loop through them
// using for loop, access them as separate entity and operate on them
})

In Meteor, how can I publish a single object from an array field?

I have the following Mongo collection:
{
id: '123456',
name: 'GameXYZ',
reviews: [
{createdBy: 'Bob', score: 5}, {createdBy: 'John', score: 8}
]
}
I would like to create a publish function that returns only the review created by Bob:
{
reviews: [
{createdBy: 'Bob', score: 5}
]
}
I've tried this:
return myCollection.find({'reviews.createdBy': 'Bob'}, {'reviews.$': 1});
The problem is Meteor returns the entire document. According to their documents, "Field operators such as $ and $elemMatch are not available on the client side yet."
My function is running on the server, so I don't know why it's not working. It does work on the Mongo Shell.
My question is: could anyone recommend a way to publish only that single object of the array, in Meteor?
This is best done like the comments example from discover meteor. Create new collection reviews. You can put what ever you need in it but it has to have the id of what ever it's a review of. That way you can publish and find it with reviews.find({reviewsId: the id of the collection; in this case 123456})

Resources