how to add additional value to array - arrays

i have an array, where all data is calculated by records from matches table:
Illuminate\Support\Collection {#1342 ▼
#items: array:4 [▼
"First team" => & array:6 [▼
"points" => 3
"scoredGoals" => 6
"goalsConceded" => 6
"wins" => 0
"loses" => 0
"draws" => 3
]
"Second team" => array:6 [▶]
"third team" => array:6 [▶]
"fourth team" => & array:6 [▶]
]
}
i need add to array image of each team (from teams table, where column image)
how can i do that?
here is my code from controller, where all data is calculated from matches table:
there is my code which i need edit:
$standings = [];
$blank = [
'points' => 0,
'scoredGoals' => 0,
'goalsConceded' => 0,
'wins' => 0,
'loses' => 0,
'draws' => 0,
];
$matches = Match::with('score', 'homeTeam', 'awayTeam')
->whereHas('score', function($query){
$query->whereNotNull('home_team_score')
->whereNotNull('away_team_score');
})
->where('league_id', '=', $league->id)
->get();
foreach ($matches as $match) {
$homeTeamScore = $match->score->home_team_score;
$awayTeamScore = $match->score->away_team_score;
if (! isset($standings[$match->homeTeam->name])) {
$standings[$match->homeTeam->name] = $blank;
}
if (! isset($standings[$match->awayTeam->name])) {
$standings[$match->awayTeam->name] = $blank;
}
$home = &$standings[$match->homeTeam->name];
$away = &$standings[$match->awayTeam->name];
$away['scoredGoals'] += $awayTeamScore;
$home['scoredGoals'] += $homeTeamScore;
$away['goalsConceded'] += $homeTeamScore;
$home['goalsConceded'] += $awayTeamScore;
switch ($homeTeamScore <=> $awayTeamScore) {
case -1:
// home lost
// swap home and away and let it fall through
$tmpHome = &$home;
$home = &$away;
$away = &$tmpHome;
case 1:
// home won
$home['points'] += 3;
$home['wins']++;
$away['loses']++;
break;
default:
// draw
$home['points']++;
$away['points']++;
$home['draws']++;
$away['draws']++;
}
}
$standings = collect($standings)->sort(function ($one, $other) {
if ($one['points'] !== $other['points']) {
return $other['points'] - $one['points']; // similar to desc
}
$oneDelta = $one['scoredGoals'] - $one['goalsConceded'];
$otherDelta = $other['scoredGoals'] - $other['goalsConceded'];
return $otherDelta - $oneDelta; // similar to desc
});
return view('admin.leagues.standings')->with([
'standings' => $standings,
]);

Going with the key of each element in your collection is the name of your team and is stored in the name column of your teams table, you can map over your collection and add in your image.
For example:
$images = [
'First team' => 'first-team.jpg',
'Second team' => 'second-team.jpg',
'Third team' => 'third-team.jpg'
];
$teamsWithImages =
collect([
"First team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
],
"Second team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
],
"Third team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
]
])->map(function ($item, $key) use ($images) {
// You would uncomment this line to retrieve the image
// from your teams table
// You also wouldn't need the use ($images) either
//$item['image'] = Teams::where('name', $key)->first()->image;
$item['image'] = $images[$key];
return $item;
})->all();
dump($teamsWithImages);
Update
Based on the code you've added, you won't need to map you can just add the image in your foreach:
if (! isset($standings[$match->homeTeam->name])) {
$standings[$match->homeTeam->name] = $blank;
$standing[$match->homeTeam->name]['image'] = $match->homeTeam->image;
}
if (! isset($standings[$match->awayTeam->name])) {
$standings[$match->awayTeam->name] = $blank;
$standing[$match->awayTeam->name]['image'] = $match->awayTeam->image;
}
Alternatively you could still use map once you have the standings sorted, but you may as well just add the image in with everything else.
$standingsWithImages = $standings
->map(function ($item, $key) {
$item['image'] = Team::where('name', $key)->first()->image;
return $item;
})->all();

Related

merging nested lists and map in ruby

I have following list of maps, how can I get values inside map out and merge them as a new list
Example:
x = [ { "key1" => [{"K1" =>"123", "K2" =>"123"}] },
{ "key1" => [{"K3" =>"23", "K4" =>"32"}] },
{ "key1" => [{"K5" =>"34", "K6" =>"23"}] }]
What I want is:
[{"K1" =>"123", "K2" =>"123"},
{"K3" =>"23", "K4" =>"32"},
{"K5" =>"34", "K6" =>"23"}]
You can try the below -
x = [ { "key1" => [{"K1" =>"123", "K2" =>"123"}] },
{ "key1" => [{"K3" =>"23", "K4" =>"32"}] },
{ "key1" => [{"K5" =>"34", "K6" =>"23"}] }]
y = x.map{|h| h.map{|i,j| j} }.flatten
print(y)
This prints the below
[{"K1"=>"123", "K2"=>"123"}, {"K3"=>"23", "K4"=>"32"}, {"K5"=>"34", "K6"=>"23"}]
x.flat_map(&:entries).group_by(&:first).map{|k,v| Hash[k, v.map(&:last)]}
as:
> x = [ { "key1" => [{"K1" =>"123", "K2" =>"123"}] },
{ "key1" => [{"K3" =>"23", "K4" =>"32"}] },
{ "key1" => [{"K5" =>"34", "K6" =>"23"}] }]
> x.flat_map(&:entries).group_by(&:first).map{|k,v| Hash[k, v.map(&:last)]}
=> [{"key1"=>[[{"K1"=>"123", "K2"=>"123"}], [{"K3"=>"23", "K4"=>"32"}], [{"K5"=>"34", "K6"=>"23"}]]}]
I hope that helpful
You can simply do as below,
x.map { |z| z.values[0][0] }
# => [{"K1"=>"123", "K2"=>"123"}, {"K3"=>"23", "K4"=>"32"}, {"K5"=>"34", "K6"=>"23"}]

Turning an array into a hash, then, adding a key => value and increment when key is present

After trying again, I think this will need an each method with a do..end. Below you will see the whole test spec to give you a breakdown of what 'cart' translates to and I have included my code so far along with the errors.
The cart starts as an array of individual items. Translate it into a hash that includes the counts for each item with the consolidate_cart method.
describe "Grocer" do
let(:items) do
[
{"AVOCADO" => {:price => 3.00, :clearance => true}},
{"KALE" => {:price => 3.00, :clearance => false}},
{"BLACK_BEANS" => {:price => 2.50, :clearance => false}},
{"ALMONDS" => {:price => 9.00, :clearance => false}},
{"TEMPEH" => {:price => 3.00, :clearance => true}},
{"CHEESE" => {:price => 6.50, :clearance => false}},
{"BEER" => {:price => 13.00, :clearance => false}},
{"PEANUTBUTTER" => {:price => 3.00, :clearance => true}},
{"BEETS" => {:price => 2.50, :clearance => false}},
{"SOY MILK" => {:price => 4.50, :clearance => true}}
]
end
let(:coupons) do
[
{:item => "AVOCADO", :num => 2, :cost => 5.00},
{:item => "BEER", :num => 2, :cost => 20.00},
{:item => "CHEESE", :num => 3, :cost => 15.00}
]
end
describe "#consolidate_cart" do
it "adds a count of one to each item when there are no duplicates" do
cart = [find_item('TEMPEH'), find_item('PEANUTBUTTER'), find_item('ALMONDS')]
result = consolidate_cart(cart)
result.each do |item, attributes|
expect(attributes.keys).to include(:count)
expect(attributes[:count]).to eq(1)
end
end
it "increments count when there are multiple items" do
avocado = find_item('AVOCADO')
cart = [avocado, avocado, find_item('KALE')]
result = consolidate_cart(cart)
expect(result["AVOCADO"][:price]).to eq(3.00)
expect(result["AVOCADO"][:clearance]).to eq(true)
expect(result["AVOCADO"][:count]).to eq(2)
expect(result["KALE"][:price]).to eq(3.00)
expect(result["KALE"][:clearance]).to eq(false)
expect(result["KALE"][:count]).to eq(1)
end
end
Here is what I have done so far:
def consolidate_cart(cart)
newCart = {}
cart.each do |item|
if cart[item.keys[0]]
cart[item.keys[0]][:count] += 1;
else
cart[item[0]]
#need to use values method to get the price and clearence added.
binding.pry
end
newCart[cart]
end
end
I am getting the following error:
1) Grocer #consolidate_cart adds a count of one to each item when there are no duplicates
Failure/Error: result = consolidate_cart(cart)
TypeError:
no implicit conversion of String into Integer
# ./grocer.rb:7:in `block in consolidate_cart'
# ./grocer.rb:5:in `each'
# ./grocer.rb:5:in `consolidate_cart'
# ./spec/grocer_spec.rb:28:in `block (3 levels) in <top (required)>''
I really could use an explanation/help. I can't get my pry to work either to really look at each piece of ode individually.
def consolidate_cart(cart)
# cart is an array of hashes
newCart = {}
cart.each do |k|
if newCart[k.keys[0]]
newCart[k.keys[0]][:count] += 1
else
newCart[k.keys[0]] = k[k.keys[0]]
newCart[k.keys[0]][:count] = 1
end
end
newCart
end
I know this is slightly old but I hope this helps someone else out.
It looks like you and I are working on the same thing. This was my solution and it passed the rspec tests.
def consolidate_cart(cart)
new_cart = {}
i = 0
while cart.length > i do
if new_cart.keys.include?(cart[i].keys[0]) == false
new_cart.merge!(cart[i])
new_cart[cart[i].keys[0]][:count] = 1
i += 1
else
new_cart[cart[i].keys[0]][:count] += 1
i += 1
end
end
p new_cart
end
I decided to use .include? as it returns a boolean value, making the if/else statement really straightforward. The .include? method searches for a match in keys. If there is not a match, send that entire hash to new_cart. If there is a match, increment :count by 1. You'll want to use a loop so that you can catch all elements inside of the starting array.

Laravel Where Collection

I am having troubles with laravel collections. This is my script:
foreach($getResult->all()['results'] as $key => $val) {
$colVal = collect($val);
$dataDiff = [];
$getWithoutLine = $colVal->except(['line_items']);
$getDiff = $colVal->only(['line_items']);
foreach($colVal->all()['line_items'] as $val1) {
if ((int)$val1['quantity'] - (int)$val1['deliveries']['quantity'] > 0) {
$getWithoutLine['status'] = 'partially_received';
$dataDiff[] = $val1;
}
}
$getWithoutLine['line_items'] = $dataDiff;
//dd($getWithoutLine);
$filtered = $getWithoutLine->whereStrict('status', 'submitted');
//dd($filtered->all());
$getFullCol[] = $filtered;
}
When dd($getWithoutLine) is executed, then collection appears like this:
Collection {#464
#items: array:24 [
"id" => "13c023aa-b471-4276-a0fc-a22d3677be91"
"status" => "submitted"
"date" => "2018-09-19"
"time" => "11:54:22"
"number" => "PO000003"
"description" => "Pesanan Pembelian, Vendor 1"
"supplier" => array:4 [
"id" => null
"code" => null
"name" => null
"classification" => null
]
"term_of_payment" => array:6 [
"due_date" => null
"due_days" => 0
"late_charge_rate" => 0.0
"discount_date" => null
"discount_days" => 0
"early_discount_rate" => 0.0
]
...
...
]
}
But when dd($filtered->all()) is executed then the result is empty. Why is that?
I can't understand what I am doing wrong.
=======
EDITED
When I change dd($filtered->all()) to dd($filtered) the result is actually same :
Collection {#463
#items: []
}
======
EDITED
When I Change $filtered = $getWithoutLine->whereStrict('status', 'submitted'); to $getWithoutLine->only('status'); the collection is work...
Collection {#468
#items: array:1 [
"status" => "submitted"
]
}

Efficient way to update values to array of hashes in ruby?

I have an array of hashes like below:
items = [ {"id" => 1, "cost" => '2.00'},
{"id" => 2, "cost" => '6.00'},
{"id" => 1, "cost" => '2.00'},
{"id" => 1, "cost" => '2.00'},
{"id" => 1, "cost" => '2.00'} ]
I would like to update the cost to '8.00' where the id = 1. I have tried with the each method like below which does work but I would like to know if there is another more efficient way of updating the values?
items.each { |h| h["cost"] = "8.00" if h["id"] == 1 }
You could just use the same object:
item_1 = {'id' => 1, 'cost' => '2.00'}
item_2 = {'id' => 2, 'cost' => '6.00'}
items = [item_1, item_2, item_1, item_1, item_1]
#=> [{"id"=>1, "cost"=>"2.00"}, {"id"=>2, "cost"=>"6.00"},
# {"id"=>1, "cost"=>"2.00"}, {"id"=>1, "cost"=>"2.00"},
# {"id"=>1, "cost"=>"2.00"}]
This makes updates trivial:
item_1['cost'] = '8.00'
items
#=> [{"id"=>1, "cost"=>"8.00"}, {"id"=>2, "cost"=>"6.00"},
# {"id"=>1, "cost"=>"8.00"}, {"id"=>1, "cost"=>"8.00"},
# {"id"=>1, "cost"=>"8.00"}]
You might consider changing your data structure from:
items = [{"id" => 1, "cost" => '2.00'}, {"id" => 2, "cost" => '6.00'},
{"id" => 1, "cost" => '2.00'}, {"id" => 1, "cost" => '2.00'},
{"id" => 1, "cost" => '2.00'}]
To a hash like this:
items = { 1 => '2.00', 2 => '6.00' }
To updating the record with id = 1 to 8.00 call:
items[1] = '8.00'
Or if you need to know the number of items, you might want to conside a structure like this:
items = { 1 => ['2.00', 4], 2 => ['6.00', 1] }
Than update like this:
items[1][0] = '8.00'
You can achieve this by using each on array
items.each{|v| v["cost"] = "8.00" if v["id"] == 1 }
Cheers!

Ruby pick up a value in hash of array to reformat into a hash

Is there a way I can pick a value in hash of array, and reformat it to be only hash?
Is there any method I can do with it?
Example
[
{
"qset_id" => 1,
"name" => "New1"
},
{
"qset_id" => 2,
"name" => "New2"
}
]
Result
{
1 => {
"name" => "New1"
},
2 => {
"name" => "New2"
}
}
You can basically do arbitary manipulation using reduce function on array or hashes, for example this will get your result
array.reduce({}) do |result, item|
result[item["qset_id"]] = { "name" => item["name"] }
result
end
You can do the same thing with each.with_object do:
array.each.with_object({}) do |item, result|
result[item["qset_id"]] = { "name" => item["name"] }
end
it's basically the same thing but you don't have to make each iteration return the result (called a 'memo object').
You could iterate over the first hash and map it into a second hash:
h1.map{|h| {h['qset_id'] => {'name' => h['name']}} }
# => [{1=>{"name"=>"New1"}}, {2=>{"name"=>"New2"}}]
... but that would return an array. You could pull the elements into a second hash like this:
h2 = {}
h1.each do |h|
h2[h['qset_id']] = {'name' => h['name']}
end
>> h2
=> {1=>{"name"=>"New1"}, 2=>{"name"=>"New2"}}

Resources