Sorting the results of _.countBy - sorting

I have a collection (Products) and I use _.countBy like this :
var totalByBrand = _.countBy(result, "Brand");
and I have this result :
{
'Brand 1 ' : 5,
'Brand 2 ' : 45,
'Brand 3 ' : 2,
...
'Brand 99 ' : 25
}
I try to sort this result to obtain that :
{
'Brand 3 ' : 2,
'Brand 1 ' : 5,
'Brand 99 ' : 25,
...
'Brand 2 ' : 45
}
Is it possible with _.sortBy() ?

Properties order cannot be guaranteed in JavaScript Does JavaScript Guarantee Object Property Order? and that means you can't sort them.
You would have to use a different structure, maybe a list of objects like {brand: ..., count: ...} and sort on on count. For example
var totalByBrand = _.countBy(products, 'Brand');
var sorted = _.chain(totalByBrand).
map(function(cnt, brand) {
return {
brand: brand,
count: cnt
}
})
.sortBy('count')
.value();
And a demo
var products = [
{Brand: "Brand 1", id: 1},
{Brand: "Brand 1", id: 2},
{Brand: "Brand 2", id: 3},
{Brand: "Brand 3", id: 4},
{Brand: "Brand 3", id: 5},
{Brand: "Brand 1", id: 6},
];
var totalByBrand = _.countBy(products, 'Brand');
var sorted = _.chain(totalByBrand).
map(function(cnt, brand) {
return {
brand: brand,
count: cnt
}
}).sortBy('count')
.value();
console.dir(
sorted
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.0/underscore-min.js"></script>

Related

laravel 9 + Vue3 + (vue-google-charts)

I'm trying to display data from laravel backend into Vue3 (vue-google-charts), but I didn't find any resources
this is a sample if my json data comming from backend
[
{
interest_oid: 1,
total_cards: 2
},
{
interest_oid: 3,
total_cards: 1
},
{
interest_oid: 5,
total_cards: 2
},
{
interest_oid: 2,
total_cards: 1
},
{
interest_oid: 4,
total_cards: 1
},
{
interest_oid: 8,
total_cards: 1
}
]
i want to display the data in GChart of type "CulomnChart"
like this one
this is my Vue component
<div class="col-lg-6">
<GChart
type="ColumnChart"
:data="chartData"
:options="chartOptions"
style="height: 100%"/>
</div>
import {GChart} from "vue-google-charts";
export default {
components: {
GChart
},
props: {
contacts_per_interests: Array,
},
data() {
return {
chartData: this.contacts_per_interests,
chartOptions: {
width: 500,
height: 300,
chart: {
title: 'Company Performance',
subtitle: 'Sales, Expenses, and Profit: 2014-2017',
}
}
}
}
}
but it's display "× Table has no columns"
any resources or suggestions please?
Your contacts_per_interests array should be look like this:
[
['interest_oid', 'total_cards'],
[1, 2],
[3, 1],
[5, 2],
[2, 1],
[4, 1],
[8, 1],
]
Adjust accordingly. Like that:
$json = '[
{
"interest_oid": 1,
"total_cards": 2
},
{
"interest_oid": 3,
"total_cards": 1
},
{
"interest_oid": 5,
"total_cards": 2
},
{
"interest_oid": 2,
"total_cards": 1
},
{
"interest_oid": 4,
"total_cards": 1
},
{
"interest_oid": 8,
"total_cards": 1
}
]';
$jsonArr = json_decode($json);
$array = [['interest_oid', 'total_cards']];
foreach ($jsonArr as $item) {
array_push($array, [$item->interest_oid, $item->total_cards]);
}

Dart: What is the proper way to sum up items in a list of Maps?

I am trying to figure out what is the best way to sum up all the same item's quantities specifically the data is formed like below:
data = [
{Item Name: Item 2, Quantity: 1},
{Item Name: Item 1, Quantity: 1},
{Item Name: Item 3, Quantity: 1},
{Item Name: Item 2, Quantity: 2},
{Item Name: Item 1, Quantity: 2},
{Item Name: Item 3, Quantity: 2},
];
and what I am trying to achieve is:
totalList = [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}];
I have tried using a tempData variable to hold onto the element and compare the rest however, this seems like it only compares that first one to the rest of the list.
var tempData = {};
var totalList = [];
data.forEach((element) {
if (tempData.isEmpty) {
tempData = element;
totalList.add(tempData);
} else {
if (tempData['Item Name'] == element['Item Name']) {
tempData['Quantity'] = tempData['Quantity'] + element['Quantity'];
totalList.add(tempData);
} else {
tempData = {
'Item Name': element['Item Name'],
'Quantity': element['Quantity']
};
totalList.add(tempData);
}
}
});
The above didnt seem to give me the output I was looking for...
What should I do instead?
Thanks for your help in advance.
Your data structure is not pretty; the 'Item Name' and 'Quantity' labels not very useful in the structure itself, so I would get rid of them and create a simplified Map<String, int> that directly maps names to quantities. Ideally you could just use the simplified structure from then on, but if you really need the explicit labels, you could convert back.
void main(List<String> args) async {
var data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
// Sum everything into a simpler data structure.
var totalCounts = <String, int>{};
for (var map in data) {
var name = map['Item Name'] as String;
var quantity = map['Quantity'] as int;
totalCounts[name] = (totalCounts[name] ?? 0) + quantity;
}
// Reformat back into the original structure.
var totalList = <Map<String, dynamic>>[
for (var entry in totalCounts.entries)
{'Item Name': entry.key, 'Quantity': entry.value},
];
// Optional: Sort.
totalList.sort((a, b) => a['Item Name'].compareTo(b['Item Name']));
print(totalList); // Prints: [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}
In real code, I additionally would add:
const nameLabel = 'Item Name';
const quantityLabel = 'Quantity';
and use those everywhere instead of the string literals to reduce opportunities for making typos.
I have created the following solution which are not that pretty but it works. The concept is to create a Map<String, Map<String, Object>> which keep track of elements we already have visited by using the "Item Name" of each element as key.
void main() {
final data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
final result = [
...data.fold(
<String, Map<String, Object>>{},
(Map<String, Map<String, Object>> sum, element) => sum
..update(
element['Item Name'] as String,
(value) => value
..update('Quantity',
(value) => (value as int) + (element['Quantity'] as int)),
ifAbsent: () => Map.from(element))).values
];
result.sort(
(a, b) => (a['Item Name'] as String).compareTo(b['Item Name'] as String));
print(result); // [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}

Merging Collection if values are equals for a specific key with Laravel

I have 2 different collections which look like this
Collection 1 :
{typesession_id: 3, formation_id: 7, codeformation: "FR8", id: 3, nomformation: "Sécurité électrique", …}
{typesession_id: 3, formation_id: 8, codeformation: "FR8", id: 4, nomformation: "Sécurité incendie", …}
Collection 2 :
{datesession: "2018-03-15", debutsession: "08:30:00", finsession: "12:00:00", typesession_id: 1, title: "Gestes d'urgence - Soignant", …}
{datesession: "2018-03-16", debutsession: "08:30:00", finsession: "12:00:00", typesession_id: 3, title: "eLearning", …}
{datesession: "2018-03-17", debutsession: "08:30:00", finsession: "12:00:00", typesession_id: 3, title: "eLearning", …}
Those 2 collection have a common key ...
I'm trying to recover the elements of the Collection 2 which have the same value for the "typesession_id" key ...
For example if my collection 1 have elements with typesession_id equal to 1 and 2, i want to have items of the collection 2 with values 1 and 2.
My newCollection should be :
{typesession_id: 3, formation_id: 7, codeformation: "FR8", id: 3, nomformation: "Sécurité électrique", datesession: "2018-03-16", debutsession: "08:30:00", finsession: "12:00:00", title: "eLearning", …}
{typesession_id: 3, formation_id: 7, codeformation: "FR8", id: 4, nomformation: "Sécurité électrique", datesession: "2018-03-17", debutsession: "08:30:00", finsession: "12:00:00", title: "eLearning", …}
{typesession_id: 3, formation_id: 8, codeformation: "FR8", id: 3, nomformation: "Sécurité incendie", datesession: "2018-03-16", debutsession: "08:30:00", finsession: "12:00:00", title: "eLearning", …}
{typesession_id: 3, formation_id: 8, codeformation: "FR8", id: 4, nomformation: "Sécurité incendie", datesession: "2018-03-17", debutsession: "08:30:00", finsession: "12:00:00", title: "eLearning", …}
In other terms : my first collection allows me to know which are the trainings an user can do ... and my second collection allows me to have information concerning sessions available for a specific type of session (typesession_id). I want to have a full list of combination based on typesession_id ...
I tried to figure it out by myself on Laravel guide but i didn't really find my solution...
I haven't tested but code likes below would probably work:
$collection1 = $collection1->groupBy('typessesion_id');
$result = $collection2->map(function($item, $key) {
$typesession_id = $item->typesession_id;
$item_clone = $item;
$data = $collection1[$typesession_id]->map(function($it, $k) use ($item_clone) {
if ($typesession_id == $it->typesession_id) {
return $item_clone->merge($it);
}
return $it;
});
return $data->merge($item);
});
dd($result);

Keying an eager-loaded relationship

I have a Business model and an Hour model. The Business model overrides the protected $with method to eager load it's hours() hasMany relationship.
When I ::first() a given business I receive something like this:
App\Business {#770
id: 5,
user_id: 5,
name: "Wehner-Hudson",
slug: "wehner-hudson",
lat: "55.33593500",
lng: "112.34818600",
created_at: "2018-01-04 13:00:48",
updated_at: "2018-01-04 13:00:48",
hours: Illuminate\Database\Eloquent\Collection {#753
all: [
App\Hour {#802
id: 13,
business_id: 5,
weekday_id: 3,
open: 1,
split_shift: 1,
},
App\Hour {#803
id: 14,
business_id: 5,
weekday_id: 5,
open: 0,
split_shift: 1,
},
App\Hour {#804
id: 15,
business_id: 5,
weekday_id: 2,
open: 1,
split_shift: 0,
},
],
},
},
],
}
I would like to key the hours: Illuminate\Database\Eloquent\Collection {#753 by weekday_id to facilitate processing on the client side. Something like this:
Illuminate\Database\Eloquent\Collection {#763
all: [
1 => App\Hour {#796
id: 1,
business_id: 1,
weekday_id: 1,
open: 1,
split_shift: 1,
},
5 => App\Hour {#767
id: 2,
business_id: 1,
weekday_id: 5,
open: 0,
split_shift: 0,
},
2 => App\Hour {#765
id: 3,
business_id: 1,
weekday_id: 2,
open: 1,
split_shift: 1,
},
],
}
I tried to use keyBy on the relationship in the Business model:
public function hours()
{
return $this->hasMany(Hour::class)->keyBy('weekday_id');
}
But it is not working, as I believe that at that point the returned object is a builder, not a collection.
Try to define an accessor, like this:
public function getHoursByWeekdayAttribute()
{
return $this->hours->keyBy('weekday_id');
}
What about using groupby in your controller.
Business::with(['hours' => function($query){ $query->groupBy('weekend_id'); }])->get();

How to use export excel and print for selected columns in datatable?

I want to use export excel and print the datatable .I use following code but not able to use both options for selected columns.
$('#example').DataTable( {
dom: 'Blfrtip',
buttons: [
{
extend: 'excel','print',
exportOptions: {
columns: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
},
}
],
"lengthMenu": [[200, 250, 500, -1], [200, 250, 500, "All"]],
"bLengthChange" : true,
initComplete: function () {
this.api().columns().every( function () {
var column = this;
var select = $('<select><option value="">Select</option></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
} );
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' )
} );
} );
}
} );
I am not figure out what happens wrong.Please help me.
{
extend: 'excel'
exportOptions: {
columns: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
},
{
extend: 'print'
exportOptions: {
columns: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
}
One of the most commonly used is the columns option which defines the columns that should be used as part of the export. This is given as a column-selector, making it simple to tell it if you want only visible columns, or a mix of the columns available.
and this is a simple of how it can be done :
function attachDataTable(tableId: string) {
let companyFunctionTable = $('#' + tableId).DataTable({
dom: 'Bfrtip',
buttons: [
//'csvHtml5'
{
extend: 'csvHtml5',
exportOptions: {
columns: [0, 1, 2]
},
className: 'btn btn-sm btn-outline-secondary',
text: `<i class="fa fa-file-csv"></i> ${i18next.t('Export to CSV')}`, titleAttr: i18next.t('Export to CSV'),
bom: true
},
],
"initComplete": function (settings, json) {
placeToolbarButton(tableId);
},
"paging": globalVar.dataTablesSettings.paging,
"stateSave": false,
"stateSaveParams": function (settings, data: any) {
data.search.search = "";
},
"order": [],
"lengthChange": false,
"pageLength": globalVar.dataTablesSettings.pageLength,
"language": {
"url": globalVar.dataTablesSettings.languageUrl
}
});
}
Please fellow that link :
https://datatables.net/extensions/buttons/examples/html5/columns.html
Don't forget to include the required JS libraries needed to display the exporting functionality.
Just modify your buttons option this way
buttons: [
{
extend: 'excel',
exportOptions: {
columns: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
},
},
{
extend: 'print',
exportOptions: {
columns: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
},
},
]
elaborated #tdymicroit answer

Resources