ruby - Array group_by sub elements - ruby

I need to group this YAML strutcture by array elements.
This is example of my YAML structure:
articles:
- title: 'Title 1'
url: 'https://example.com'
data: July 21, 2017
categories:
- 'category 1'
- 'category 2'
- title: 'Title 2'
url: 'https://example.com'
data: July 23, 2017
categories:
- 'category 2'
Result I need is this or similar:
['category 1' =>
[
{title: 'Title 1', url: 'https://example.com', data: July 21, 2017, categories: ['category 1', 'category 2']}
],
'category 2' => [
{title: 'Title 1', url: 'https://example.com', data: July 21, 2017, categories: ['category 1', 'category 2']},
{title: 'Title 2', url: 'https://example.com', data: July 23, 2017, categories: ['category 2']}
]
]
Can you help me? Thank you in advance
UPDATE:
I have tried this:
articles.group_by(&:categories).map{|v, a| [v, a] }
but key is not single category, but categories elements. I think I need a more loop but after some trials I haven't get the result.
Sorry for this, but I newbie for ruby
UPDATE 2:
Wrong result is:
[
[
[
"category 1",
"category 2"
],
[
{
"title": "Title 1",
"url": "https://example.com",
"data": "July 21, 2017",
"categories": [
"category 1",
"category 2"
]
}
]
],
[
[
"category 2"
],
[
{
"title": "Title 2",
"url": "https://example.com",
"data": "July 23, 2017",
"categories": [
"category 2"
]
}
]
]
]

It seems, in this case, the plain old good reducer would suit your needs better:
articles.each_with_object({}) do |article, acc|
acc.merge! article.categories.map { |c| [c, article] }.to_h
end
or even:
articles.map do |article|
article.categories.map { |c| [c, article] }.to_h
end.reduce(&:merge)

Do you need a group_by? Why not an easy nested loop?
result = {}
articels.each do |article|
article.categories.each do |cat|
result[cat] ||= []
result[cat] << article
end
end

Related

RxJS groupBy to multidimensional array

I've been attempting multiple combinations of operators and can't quite get the output I want. Give an array of events:
const events = [
{ day: 1, title: 'Event 1' },
{ day: 1, title: 'Event 2' },
{ day: 1, title: 'Event 3' },
{ day: 2, title: 'Event 4' },
{ day: 2, title: 'Event 5' },
{ day: 2, title: 'Event 6' },
{ day: 'both', title: 'Sandbox 1' },
{ day: 'both', title: 'Sandbox 2' },
]
I'd like an output like so:
[
[
{
"day": 1,
"title": "Event 1"
},
{
"day": 1,
"title": "Event 2"
},
{
"day": 1,
"title": "Event 3"
}
],
[
{
"day": 2,
"title": "Event 4"
},
{
"day": 2,
"title": "Event 5"
},
{
"day": 2,
"title": "Event 6"
}
],
[
{
"day": "both",
"title": "Shared 1"
},
{
"day": "both",
"title": "Shared 2"
}
]
]
The only way I've been able to get this is by subscribing and pushing the result into another array. Ideally the rx chain would build it before subscribing, but I can't quite get it.
Here's what I have that outputs the result above:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
).subscribe(next => {
this.all.push(next)
console.log(this.all)
})
To accumulate the groups into an outer array, you can use another toArray operator after the mergeMap:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
toArray(),
).subscribe(results => console.log(results))
The resultant observable will emit only once and will emit a single array containing all of the group arrays.

Laravel collection: return only relationship and key

I have a collection that resembles this:
$a = Model::with(['sub' => function($q) {
$q->select('id', 'name')
}])->get();
This returns the following collection:
{
0: {
id: 0001,
name: "item 1",
type: "type a"
'sub' [
{
'id': 10001,
'name': "sub Item 1"
},
{
'id': 10002,
'name': "sub Item 2"
}
]
},
1: {
id: 0002,
name: "item 2",
type: "type a"
'sub' [
{
'id': 11001,
'name': "sub Item 4"
},
{
'id': 11002,
'name': "sub Item 5"
}
]
}
What I am trying to do is key the parent items by their ids and only return the relationship. For example
{
0001: {
'sub' [
{
'id': 10001,
'name': "sub Item 1"
},
{
'id': 10002,
'name': "sub Item 2"
}
]
},
0002: {
'sub' [
{
'id': 11001,
'name': "sub Item 4"
},
{
'id': 11002,
'name': "sub Item 5"
}
]
}
I cannot seem to get this to work. I have tried many variations including:
$a = Model::with(['sub' => function($q) {
$q->select('id', 'name')
}])->pluck('sub', 'id');
This doesn't work as 'Pluck' is obviously looking for a a property of the parent model with the name of 'sub' which doesn't exit. Is there a way to achieve this?
Thanks
You were almost there. You will need to do ->get() before the pluck().
$a = Model::with([
'sub' => function ($q) {
$q->select('id', 'name');
},
])->get()->pluck('sub', 'id');
The pluck() used in your example will be the query builder version of pluck rather than the collection version.
use keyBy to use your pk as array index.
https://laravel.com/docs/5.4/collections#method-keyby
However ignoring other fields you probably would need each and filter. Wouldn't it be easier to select Sub::where(...) and then use collection groupBy on the parent_id: https://laravel.com/docs/5.4/collections#method-groupby
So something like Sub::where(...)->get()->groupBy('parent_id')

jqGrid and jqPivot: Keeping spaces in pivoted column names?

I'm using jqGrid with the jqPivot API.
The problem I'm encountering is that jqPivot removes the spaces from the pivoted column names. Is there any way to change this behaviour?
eg.
var mydata = [
{id: "1", emp:"Michelle", product:"A A", sold:"8"},
{id: "2", emp:"Tania", product:"A A", sold:"3"},
{id: "6", emp:"Mark", product:"A B", sold:"1"},
{id: "3", emp:"Tommy", product:"A B", sold:"5"},
{id: "4", emp:"Dave", product:"B B", sold:"2"},
{id: "5", emp:"Carol", product:"B B", sold:"5"},
];
var grid = $("#grid");
grid.jqGrid('jqPivot',
mydata, {
xDimension: [{
dataName: 'id',
label: 'ID',
width: 90
}, {
dataName: 'emp',
label: 'Employee',
width: 90
}, ],
yDimension: [{
dataName: 'product'
}],
aggregates: [{
member: 'sold',
aggregator: 'sum',
width: 50,
label: 'Sold'
}, ],
colTotals: true
}, {
width: "100%",
height: "100%",
pager: "#pager",
caption: "Daily Sales"
});
http://jsfiddle.net/aUDHx/968/
Instead of "A A" and "A B" etc. it displays the columns as "AA" and "AB".
I agree that it's a problem. The reason is the line of jqPivot code. As a quick and dirty workaround I could suggest you to use converter which replace the space to some other character like _,   ( ) or .
yDimension: [{
dataName: 'product',
converter: function (val) {return val.replace(/\s/g, ' ');}
}],
See the modified demo http://jsfiddle.net/OlegKi/aUDHx/970/.

Ruby, unique hashes in array based on multiple fields

I'd like to get back an array of hashes based on sport and type combination
I've got the following array:
[
{ sport: "football", type: 11, other_key: 5 },
{ sport: "football", type: 12, othey_key: 100 },
{ sport: "football", type: 11, othey_key: 700 },
{ sport: "basketball", type: 11, othey_key: 200 },
{ sport: "basketball", type: 11, othey_key: 500 }
]
I'd like to get back:
[
{ sport: "football", type: 11, other_key: 5 },
{ sport: "football", type: 12, othey_key: 100 },
{ sport: "basketball", type: 11, othey_key: 200 },
]
I tried to use (pseudocode):
[{}, {}, {}].uniq { |m| m.sport and m.type }
I know I can create such array with loops, I'm quite new to ruby and I'm curious if there's a better (more elegant) way to do it.
Try using Array#values_at to generate an array to uniq by.
sports.uniq{ |s| s.values_at(:sport, :type) }
One solution is to build some sort of key with the sport and type, like so:
arr.uniq{ |m| "#{m[:sport]}-#{m[:type]}" }
The way uniq works is that it uses the return value of the block to compare elements.
require 'pp'
data = [
{ sport: "football", type: 11, other_key: 5 },
{ sport: "football", type: 12, othey_key: 100 },
{ sport: "football", type: 11, othey_key: 700 },
{ sport: "basketball", type: 11, othey_key: 200 },
{ sport: "basketball", type: 11, othey_key: 500 }
]
results = data.uniq do |hash|
[hash[:sport], hash[:type]]
end
pp results
--output:--
[{:sport=>"football", :type=>11, :other_key=>5},
{:sport=>"football", :type=>12, :othey_key=>100},
{:sport=>"basketball", :type=>11, :othey_key=>200}]

Ruby nested hash syntax & structure

I'm building a tree of html elements, class names and their counts.
How would I structure this code with the proper syntax?
$html = {
:p => [
{ 'quote' => 10 },
{ 'important' => 4 }
],
:h2 => [
{ 'title' => 33 },
{ 'subtitle' => 15 }
]
}
I'm confused by the nested hash syntax. Thanks for the help setting me straight.
A simple way to structure a HTML tree could be:
html = [
{ _tag: :p, quote: 10, important: 4 },
{ _tag: :h2, title: 33, subtitle: 15 },
]
Where html[0][:_tag] is the tag name, and other attributes are accessible through html[0][attr]. The root element is an array since multiple elements of the same type (multiple paragraphs) could exist in the same namespace and a hash would only store the last added one.
A more advanced example which would allow nested contents:
tree = { _tag: :html, _contents: [
{ _tag: :head, _contents: [
{ _tag: :title, _contents: "The page title" },
]},
{ _tag: :body, id: 'body-id', _contents: [
{ _tag: :a, href: 'http://google.com', id: 'google-link', _contents: "A link" },
]},
]}
After defining the HTML element you don't assign another hash, but a list and from your question title I guess you want to nest another hash directly. Thus you do not start with a square bracket, but with another curly brace:
$html = {
:p => { 'quote' => 10, 'important' => 4 },
:h2 => { 'title' => 33, 'subtitle' => 15 }
}
#Example
puts $html[:p]['quote']
Which will print:
10
Take a look at the constructor documentation of Hash, there are different ways to initialize hashes, maybe you find a more intuitive one.

Resources