Conditionally add properties to elements of array with yq (version 4) - arrays

I have a YAML document that contains an array. I would like to conditionally add properties to the elements of that array using yq version 4 from mikefarah.
Here is a sample YAML document.
name: "My Pets"
pets:
- name: "cat"
age: 8
- name: "dog"
age: 3
- name: "mouse"
age: 1
I would like to transform this into,
name: "My Pets"
pets:
- name: "cat"
age: 8
shots: cat.upToDate
- name: "dog"
age: 3
shots: dog.upToDate
- name: "mouse"
age: 1
shots: mouse.upToDate
where we add a shots property to each element of pets. The value of shots should be whatever the name value is, dot, upToDate.
I'm trying something like this,
yq eval '.pets[] | select(.name == "cat").shots = "cat.upToDate"' test.yaml
but that produces,
name: "cat"
age: 8
shots: cat.upToDate
name: "dog"
age: 3
name: "mouse"
age: 1
I need to preserve the entire original YAML document and just insert the shots property.
This is close but missing all of the other pets.
yq eval '.pets = (.pets[] | select(.name == "cat").shots = "cats.upToDate")' test.yaml
It produces,
name: "My Pets"
pets:
name: "cat"
age: 8
shots: cats.upToDate
I'm thinking maybe we could store the name of the pet in a variable and reference that later, but v4 is brand new to me today.
I would prefer to have a one-liner so that I don't have to filter on .name. This array has less than 10 elements so I could easily hard-code the name and call yq 10 times.
Any thoughts or suggestions? Many thanks, Weldon

Use |=, e.g. like so:
yq eval '.pets[] |= (.shots = (.name + ".upToDate"))' pets.yaml

Related

Combining LEFT, SEARCH and REGEXREPLACE

So, I'm helping out someone, and I'm trying to extract only the name of the cancer in the column, without including "Deaths -".
In Column A, the entries all have this pattern, each string below being in it's own separate row...
Deaths - Prostate cancer - Sex: Both - Age: Age-standardized (Rate)
Deaths - Breast cancer - Sex: Both - Age: Age-standardized (Rate)
Deaths - Testicular cancer - Sex: Both - Age: Age-standardized (Rate)
Deaths - Non-melanoma cancer - Sex: Both - Age: Age-standardized (Rate)
Deaths - Tracheal, bronchus, and lung cancer - Sex: Both - Age: Age-standardized (Rate)
I've been able to extract the name of the cancer, including removing the word "cancer" with this LEFT and SEARCH formula below...
=LEFT(A2, SEARCH("cancer", A2)-1)
Resulting in the following...
Deaths - Breast
Deaths - Testicular
Deaths - Non-melanoma
Deaths - Tracheal, bronchus, and lung
But, I can't seem to combine REGEXREPLACE with LEFT and SEARCH in one formula to also take out "Deaths" and the - (dash), leaving only the name of the cancer.
So, the desired result is below...
Breast
Testicular
Non-melanoma
Tracheal, bronchus, and lung
Thanks for any help you can provide.
try simple:
=INDEX(IFNA(REGEXEXTRACT(A1:A6, "- (.+) cancer")))

In a Ruby on Rails app, I'm trying to loop through an array within a hash within an array. Why am I getting "syntax error" message?

I have a Ruby on Rails application to enter results and create a league table for a football competition.
I'm trying to input some results by creating records in the database through heroku and I get error messages.
The application isn't perfectly designed: to enter the results, I have to create the fixtures and enter the score for each team. Then, independently I have to record each goal scorer, creating a record for each goal which is either associated with an existing player or requires me to firstly create a new player and then create the goal.
When I ran the code below heroku, I got this error:
syntax error, unexpected ':', expecting keyword_end
Maybe I'm missing something simple about lopping through an array within a hash?
Thank you for any advice!
coalition = Team.find_by(name: "Coalition")
moscow_rebels = Team.find_by(name: "Moscow Rebels")
red_star = Team.find_by(name: "Red Star")
unsanctionables = Team.find_by(name: "The Unsanctionables")
cavalry = Team.find_by(name: "Cavalry")
galactics = Team.find_by(name: "The Galactics")
happy_sundays = Team.find_by(name: "Happy Sundays")
hardmen = Team.find_by(name: "Hardmen")
international = Team.find_by(name: "International")
evropa = Venue.find_by(name: "Evropa")
s28 = Season.find_by(number: 28)
start_time = DateTime.new(2020,9,6,11,0,0,'+03:00')
scheduled_matches_1 =
[
{team_1: cavalry, team_1_goals: 1, team_1_scorers: ["Minaev"], team_2_goals: 6, team_2_scorers: ["Kovalev", "Kovalev", "Kovalev", "Thomas", "Thomas", "Grivachev"], team_2: coalition, time: start_time, venue: evropa, season: s28},
{team_1: hardmen, team_1_goals: 4, team_1_scorers: ["Jones", "Jones", "Jones", "Fusi"], team_2_goals: 2, team_2_scorers: ["Kazamula", "Ario"], team_2: galactics, time: start_time + 1.hour, venue: evropa, season: s28},
{team_1: international, team_1_goals: 9, team_1_scorers: ["Kimonnen", "Kimonnen", "Kimonnen", "Burya", "Burya", "Zakharyaev", "Zakharyaev", "Lavruk", "Rihter"], team_2_goals: 0, team_2_scorers: [], team_2: happy_sundays, time: start_time+2.hours, venue: evropa, season: s28}
]
scheduled_matches.each do |match|
new_fixture = Fixture.create(time: match[:time], venue: match[:venue], season: match[:season])
tf1 = TeamFixture.create(team: match[:team_1], fixture: new_fixture)
tf2 = TeamFixture.create(team: match[:team_2], fixture: new_fixture)
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match{:team_1_goals})
ts2 = TeamScore.create(team_fixture: tf2, total_goals: match{:team_2_goals})
match[:team_1_scorers].each do |scorer|
if Player.exists?(team: tf1.team, last_name: scorer)
Goal.create(team_score: ts1, player: Player.find_by(last_name: scorer))
else
new_player = Player.create(team: tf1.team, last_name: scorer)
Goal.create(team_score: ts1, player: new_player)
end
end
match[:team_2_scorers].each do |scorer_2|
if Player.exists?(team: tf2.team, last_name: scorer_2)
Goal.create(team_score: ts2, player: Player.find_by(last_name: scorer_2))
else
new_player = Player.create(team: tf2.team, last_name: scorer_2)
Goal.create(team_score: ts2, player: new_player)
end
end
end
It looks like you are using braces when you meant to use brackets to access the hash. Below is one of the issues, but the same issue is in ts2.
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match{:team_1_goals})
should be match[:team_1_goals]
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match[:team_1_goals])
It may be because you have scheduled_matches_1 at the top and scheduled_matches.each do... further down.
But the real issue here is that your variable names match the data content, rather than being used to hold the content. If a new team joins your league, you have to change the code. Next week, you are going to have to change the hard-coded date value. Your scheduled_matches_1 data structure includes the active record objects returned by the first set of Team.findByName() calls. It would be easier to fetch these objects from the database inside your loops, and just hold the team name as a string in the hash.
There is some duplication too. Consider that each fixture has a home team and an away team. Each team has a name, and an array (possibly empty) of the players who scored. We don't need the number of goals; we can just count the number of players in the 'scorers' array. The other attributes, like the location and season belong to the fixture, not the team. So your hash might be better as
{
"fixtures": [
{
"home": {
"name": "Cavalry",
"scorers": [
"Minaev"
]
},
"away": {
"name": "Coalition",
"scorers": [
"Kovalev",
"Kovalev",
"Kovalev",
"Thomas",
"Thomas",
"Grivachev"
]
},
"venue": "Evropa",
"season": "s28"
}
]
}
because then you can create a reusable method to process each team. And maybe create a new method that returns the player (which it either finds or creates) which can be called by the loop that adds the goals.
Also, as it stands, I'm not sure the code can handle 'own goals', either. Perhaps something for a future iteration :)

Ansible loop over a list of dicts with count as a key

Say I have a list of dicts like the following:
my_dummy_list:
- { name: x, count: 2 }
- { name: y, count: 5 }
- { name: z, count: 1 }
...
I need to iterate over it so a task gets applied the count times for each name.
I tried to use with_subelements, but it requires the second argument to be a list, and thus I must transform counts to range() like
my_dummy_list:
- { name: x, count: "{{ range(1, 3) | list }} }
- { name: y, count: "{{ range(1, 6) | list }} }
...
which is unreadable, unobvious and mistakable, I really want to avoid it.
I also had an idea of using templating but it would overencumber the playbook, it's already pretty much complicated.
Will appreciate any help.
PS my task looks as follows (very simplified)
- name: my_task
shell: echo {{item.0.name}}_{{item.1}}
with_subelements:
- "{{ my_dummy_list }}"
- count
and I expect the following output
x_1
x_2
y_1
...
y_5
z_1

read values as string of yaml with libyaml

I'm need simple example for using libyaml to get all keys+values as strings from yaml file.
lets say i have this yaml file:
Active Groups:
btcoex: yes
datapath: no
Header:
TLV_data_version: 1
command id: 0xf1
group id: 0x01
btcoex:
enabel ATS:
Active: yes
Apply_point: APPLY_POINT_AFTER_ALIVE
selection:
set: 1
table: 3
cpu: 1
how can I just print all the keys and values?

AngularFire custom order by ranking

I'm trying to sort teams by ranking, using AngularFire and Firebase.
In Firebase I have 4 teams where I store only the name.
I also store matches, which have a reference to both teams disputing that match and the score for each one.
The matches node looks like this:
matches
-KQgphN_5692GySN0Oxz
home_team: teamA
away_team: teamB
score
home: 1
away: 2
-KQlu6XLak6LgAr9cTty
home_team: teamC
away_team: teamD
score
home: 2
away: 2
And the teams node:
teams
teamA
name: "Team A"
teamB
name: "Team B"
teamC
name: "Team C"
teamD
name: "Team D"
So, I need to order these teams by vitories, draws and losses by watching the results in realtime.
I have a ng-repeat that lists teams like this:
<li ng-repeat="team in teams">{{team.name}}</li>
So, how can I order these teams by wins, taking in account that a win is equivalent to 3 points, a draw is 1 point and a loss is 0 points?
With the above matches example, the ranking should be:
1 - Team B
2 - Team C
3 - Team D
4 - Team A
You can order a Firebase Database query by a nested value, as long as that nested value is at a fixed path. This means you'll need to store the score for each team, e.g.
teams
teamA
name: "Team A"
score: 20
teamB
name: "Team B"
score: 12
teamC
name: "Team C"
score: 42
teamD
name: "Team D"
score: 31
With this structure, you can load the top teams in order with:
var leaders = ref.child('teams').orderByChild('score').limitToLast(3);
leaders.on('value', function(snapshot) {
leaders.forEach(function(leaderSnapshot) {
console.log(leaderSnapshot.child('name').val());
});
});
This will print:
Team A
Team D
Team C
So to get the leaderboard, you'll need to invert them.

Resources