Ansible - keys missing after changing values in a dict - dictionary

I want to change all the values "b" in a way that I will divide it with some number.
Here is the code:
- name: code
hosts: localhost
gather_facts: false
vars:
dict1: [{"a": 1, "b": 2, "c": 3}, {"a": 5, "b": 5, "c": 6},{"a": 8, "b": 9, "c": 10}]
dict2: |
[
{% for i in dict1 %}
{{ i.a, (i.b/2)|int, i.c }},
{% endfor %}
]
tasks:
- debug:
var: dict2|type_debug
- debug:
var: dict2
Problem with this is that I've got just values and "keys" are missing
ok: [localhost] => {
"dict2": [
[
1,
1,
3
],
[
5,
2,
6
],
[
8,
4,
10
]
]
What should I change to include keys too?
Also, not that important, but I've got [ ] instead { } for each item in the loop (simple replacement [] with {} in the variable dict2 doesn't work).
Thanks!

The variable dict1 is a list of dicts. This means that you cannot simply define a list of values, but must also create a dict again.
There are surely different approaches for this, one is the following:
dict1: [{"a": 1, "b": 2, "c": 3}, {"a": 5, "b": 5, "c": 6},{"a": 8, "b": 9, "c": 10}]
dict2: |
[
{% for i in dict1 %}
{{ dict( ['a', 'b', 'c'] | zip( [i.a, (i.b/2)|int, i.c] ) ) }},
{% endfor %}
]
a list with the values a, b and c is defined
another list with the values for a, b, c is created
both lists are connected by zip().
the resulting zip lists are converted to a dict by dict().
The result of - debug: var=dict2 looks like this:
TASK [debug] **********************
ok: [localhost] => {
"dict2": [
{
"a": 1,
"b": 1,
"c": 3
},
{
"a": 5,
"b": 2,
"c": 6
},
{
"a": 8,
"b": 4,
"c": 10
}
]
}

Related

Add items to dict in elixir

I have a nested dict in elixir, from which I want to save the latest items in a new dict.
sorted_slides = [
%{
id: 1,
visual_events: [
%{entity_id: 1, payload: "abc"},
%{entity_id: 2, payload: "def"}
]
},
%{
id: 2,
visual_events: [
%{entity_id: 2, payload: "yui"},
%{entity_id: 3, payload: "def"},
%{entity_id: 4, payload: "ghi"},
]
},
%{
id: 3,
visual_events: [
%{entity_id: 2, payload: "ert"},
%{entity_id: 4, payload: "poi"},
]
}
]
dict = %{}
Enum.each(sorted_slides, fn slide ->
Enum.each(slide.visual_events, fn ve ->
eid = ve.entity_id
dict = Map.put(dict, eid, ve)
IO.inspect(dict)
end)
end)
IO.inspect(dict)
My original data structure contains items that may be overwritten by newer items. I want the new dict to be:
dict = %{
1 => %{entity_id: 1, payload: "abc"},
2 => %{entity_id: 2, payload: "ert"},
3 => %{entity_id: 3, payload: "def"},
4 => %{entity_id: 4, payload: "poi"}
}
I want the dict to save the changes made to it by each iteration, but I guess that scoping works different from some other languages here.
How would I achieve this in Elixir?
You can use Enum.flat_map/2 to extract the inner elements, and Map.new/2 to construct a new map from those elements. Map.new/2 will ensure the latest element prevails when there are duplicate keys.
sorted_slides
|> Enum.flat_map(fn %{visual_events: items} -> items end)
|> Map.new(fn %{entity_id: id} = map -> {id, map} end)
Result:
%{
1 => %{entity_id: 1, payload: "abc"},
2 => %{entity_id: 2, payload: "ert"},
3 => %{entity_id: 3, payload: "def"},
4 => %{entity_id: 4, payload: "poi"}
}
In the case you want to build a structure within a "loop", you can most of the times reach for Enum.reduce/3:
Enum.reduce(sorted_slides, %{}, fn slide, acc ->
Enum.into(slide.visual_events, acc, fn event ->
{event.entity_id, event}
end)
end)
The inner loop could be implemented with Enum.reduce/3 as well, but Enum.into/3 makes it slightly more compact.
Enum.each/2 is only meant to perform side-effects (like printing) but doesn't return any actual result, it just always returns :ok.
I guess that scoping works different from some other languages here.
Exactly, in Elixir you don't mutate existing structures, you create new structures and need to pass them around. This is typically the case of our acc accumulator above.
Side note: in Elixir, these are not called dicts but maps. There have been deprecated dicts structure in the past.

jq grab keys from array of objects

Let's say I have the following array:
[
{
"a": 1,
"b": 2,
"c": 3,
"d": 4
},
{
"a": 10,
"b": 20,
"c": 30,
"d": 40
},
{
"a": 100,
"b": 200,
"c": 300,
"d": 400
}
]
I want to generate a new array with just the a and b keys. I know I can do it like this:
ARRAY | jq '. | map({ a: .a, b: .b })'
I'm not renaming any of the keys so having to type a and b seems a bit verbose. Is there a cleaner way to do this?
You will have to type a and b once in order to specify which ones to keep:
jq 'map({a,b})'
Alternatively, specify what to delete, here .c and .d:
jq 'map(del(.c,.d))'
In any case, .| is also superfluous.

loop over list in elixir without creating nil values

I have an interesting situation. I'm looping over a list several times and I don't know how to produce the list I want. I'm essentially trying to order the second tuple in a list of tuples according to the order of an outside list.
aclist = [{2,4},{2,6},{4,1},{4,8},{1, 2},{1,5},{3,3},{3,7}]
plist = [1,2,3,4]
newplist =
for pid <- plist do
Enum.map(aclist, fn({p_id,c_id}) ->
if p_id == pid do
c_id
end
end)
end
the output from this code is:
[[2, 5, nil, nil, nil, nil, nil, nil], [nil, nil, 4, 6, nil, nil, nil, nil],
[nil, nil, nil, nil, 3, 7, nil, nil], [nil, nil, nil, nil, nil, nil, 1, 8]]
I need the output to be [2,5,4,6,3,7,1,8] but that would require me to loop over it again in a nested loop to pull those numbers out. So obviously I'm missing something, how do I loop over it and pull out the correct data the first time?
for is the perfect thing to use here. It allows iterating over multiple lists while producing a flat list as result and also allows filtering:
iex(1)> aclist = [{2,4},{2,6},{4,1},{4,8},{1, 2},{1,5},{3,3},{3,7}]
[{2, 4}, {2, 6}, {4, 1}, {4, 8}, {1, 2}, {1, 5}, {3, 3}, {3, 7}]
iex(2)> plist = [1,2,3,4]
[1, 2, 3, 4]
iex(3)> for pid <- plist, {p_id, c_id} <- aclist, p_id == pid, do: c_id
[2, 5, 4, 6, 3, 7, 1, 8]

VisJS graph2d draw order / groupOrder

Is there an equivalent groupOrder option for graph2d as there is for the timeline widget? http://visjs.org/docs/timeline/#Configuration_Options
Looking to draw bar charts in a specific order to handle overlapping.
The group order is determined by the order how you add groups, unless you set the ids as integers.
This is a example where you set the ids with strings:
a = new vis.DataSet()
-> DataSet {_options: Object, _data: Object, length: 0, _fieldId: "id", _type: Object…}
a.add([{id:"b"}, {id: "a"}, {id: "c"}])
-> ["b", "a", "c"]
a.getIds()
-> ["b", "a", "c"]
But when you create a dataset where the ids are integers, it will sort the datagroups based on the integers:
b = new vis.DataSet()
-> DataSet {_options: Object, _data: Object, length: 0, _fieldId: "id", _type: Object…}
b.add([{id:2}, {id: 3}, {id: 1}])
-> [2, 3, 1]
b.getIds()
-> [1, 2, 3]
When you mix the integers and strings it will sort the integers first and then then leave the strings unsorted.
c = new vis.DataSet()
DataSet {_options: Object, _data: Object, length: 0, _fieldId: "id", _type: Object…}
c.add([{id:"b"}, {id: 2}, {id: "a"} , {id: 1}])
["b", 2, "a", 1]
c.getIds()
[1, 2, "b", "a"]

Iterating Through a Dictionary in Swift

I am a little confused on the answer that Xcode is giving me to this experiment in the Swift Programming Language Guide:
// Use a for-in to iterate through a dictionary (experiment)
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25]
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
largest
I understand that as the dictionary is being transversed, the largest number is being set to the variable, largest. However, I am confused as to why Xcode is saying that largest is being set 5 times, or 1 time, or 3 times, depending on each test.
When looking through the code, I see that it should be set 6 times in "Prime" alone (2, 3, 5, 7, 11, 13). Then it should skip over any numbers in "Fibonacci" since those are all less than the largest, which is currently set to 13 from "Prime". Then, it should be set to 16, and finally 25 in "Square", yielding a total of 8 times.
Am I missing something entirely obvious?
Dictionaries in Swift (and other languages) are not ordered. When you iterate through the dictionary, there's no guarantee that the order will match the initialization order. In this example, Swift processes the "Square" key before the others. You can see this by adding a print statement to the loop. 25 is the 5th element of Square so largest would be set 5 times for the 5 elements in Square and then would stay at 25.
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25]
]
var largest = 0
for (kind, numbers) in interestingNumbers {
println("kind: \(kind)")
for number in numbers {
if number > largest {
largest = number
}
}
}
largest
This prints:
kind: Square
kind: Prime
kind: Fibonacci
let dict : [String : Any] = ["FirstName" : "Maninder" , "LastName" : "Singh" , "Address" : "Chandigarh"]
dict.forEach { print($0) }
Result would be
("FirstName", "Maninder")
("LastName", "Singh")
("Address", "Chandigarh")
This is a user-defined function to iterate through a dictionary:
func findDic(dict: [String: String]) {
for (key, value) in dict {
print("\(key) : \(value)")
}
}
findDic(dict: ["Animal": "Lion", "Bird": "Sparrow"])
// prints…
// Animal : Lion
// Bird : Sparrow
If you want to iterate over all the values:
dict.values.forEach { value in
// print(value)
}
Here is an alternative for that experiment (Swift 3.0). This tells you exactly which kind of number was the largest.
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var whichKind: String? = nil
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
whichKind = kind
largest = number
}
}
}
print(whichKind)
print(largest)
OUTPUT:
Optional("Square")
25
You can also use values.makeIterator() to iterate over dict values, like this:
for sb in sbItems.values.makeIterator(){
// do something with your sb item..
print(sb)
}
You can also do the iteration like this, in a more swifty style:
sbItems.values.makeIterator().forEach{
// $0 is your dict value..
print($0)
}
sbItems is dict of type [String : NSManagedObject]

Resources