Remove duplicate items in objects array with lodash.js - javascript

I'm trying to remove duplicate items using lodash.js but I can't make it works properly.
This is the structure of an object in the array:
{
label: 'tagA',
value: 1
}
So let say I have this array:
var objectsArray = [
{
label: 'tagA',
value: 1
},
{
label: 'tagB',
value: 2
},
{
label: 'tagC',
value: 3
},
{
label: 'tagB',
value: 4
},
{
label: 'tagB',
value: 5
},
];
I made this piece of code with _.uniqBy() function from lodash.js to try to remove the elements of array with the same labels, but it dosn't work as I expected:
var uniq = _.uniqBy(objectsArray, function(o){
return o.label;
});
I based on some sample found here and there and lodash documentation of course but I have a lack of knowledge in this regard so any help it will super appreciate it.
Thanks.

Make sure that you use proper namings, that code works for me:
var arr = [
{
label: 'tagA',
value: 1
},
{
label: 'tagB',
value: 2
},
{
label: 'tagC',
value: 3
},
{
label: 'tagB',
value: 4
},
{
label: 'tagB',
value: 5
},
];
var uniq = _.uniqBy(arr, function(o){
return o.label;
});
console.log(uniq); // >> Returned an array with first 3 objects from array arr

If you want to make sure you can use uniqWith();
This works for me
var data = [
{
label: 'tagA',
value: 1
},
{
label: 'tagB',
value: 2
},
{
label: 'tagC',
value: 3
},
{
label: 'tagB',
value: 4
},
{
label: 'tagB',
value: 5
},
];
var filtered = _.uniqWith(data, function(first, second){
return first.label === second.label
});

I think the second example is just what you need uniqBy:
// The `_.property` iteratee shorthand.
_.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
// → [{ 'x': 1 }, { 'x': 2 }]

Related

Conditional object properties in React

I am trying to use conditional statements (&& or ?) inside an object that is returned within method in React component. Is it possible?
The issue is I want to add to condition multiple properties. It works with just one like this:
arr: [
isInsidePlan
? {
label: 'anything1'
value: 1,
} :
{
label: 'anything2'
value: 2,
},
{
label: 'anything3'
value: 3,
},
{
label: 'anything4'
value: 4,
},
],
What I would like to achieve is to do it with all other properties inside else condition. Like this: (this code doesn't work)
arr: [
isInsidePlan
? ({
label: 'anything1'
value: 1,
}) :
({
label: 'anything2'
value: 2,
},
{
label: 'anything3'
value: 3,
},
{
label: 'anything4'
value: 4,
})
],
I get an error:
Left side of comma operator is unused and has no side effects.
You should make the if condition outside the array itself.
Something like:
arr: isInsidePlan ? [
{
label: 'anything1'
value: 1,
}] :
[{
label: 'anything2'
value: 2,
},
{
label: 'anything3'
value: 3,
},
{
label: 'anything4'
value: 4,
}]
],

Generate permutations of Javascript object keys/values

I need to create a nested hierarchy of options. The options are keys on an array with several sub-options as nested objects.
I need to generate a nested hierarchy from this object.
Starting with an object like this:
const starterObject = {
id1: {
1: { value: "A" },
2: { value: "B" },
3: { value: "C" },
},
id2: {
1: { value: 10 },
2: { value: 20 },
},
};
I need to end up with an object of permutations like this:
const permutations2 = {
1: [{ value: "A" }, { value: 10 }],
2: [{ value: "A" }, { value: 20 }],
3: [{ value: "B" }, { value: 10 }],
4: [{ value: "B" }, { value: 20 }],
5: [{ value: "C" }, { value: 10 }],
6: [{ value: "C" }, { value: 20 }],
};
I tried something like this:
const starterObject = {
id1: {
1: { value: "A" },
2: { value: "B" },
3: { value: "C" },
},
id2: {
1: { value: 10 },
2: { value: 20 },
},
};
const permutationMatrix = [];
Object.keys(starterObject["id1"]).forEach(key2 =>
Object.keys(starterObject["id2"]).forEach(key1 =>
permutationMatrix.push([
starterObject["id1"][key2],
starterObject["id2"][key1],
])
)
);
console.log(permutationMatrix)
But the problem is that the keys are hardcoded. The actual object will have 1-5 keys (id1 - id5) and any number of nested objects.
I think this will require recursion, but I'm not sure how to proceed from here.
Reduce, entries, and values can help and there is no need for recursion.
const starterObject = {
id1: {
1: { value: "A" },
2: { value: "B" },
3: { value: "C" },
},
id2: {
1: { value: 10 },
2: { value: 20 },
},
id3: {
1: { value: 100 }
}
};
var entries = Object.entries(starterObject)
var out = entries.reduce((arr, group) => {
const itms = Object.values(group)[1]
const vals = Object.values(itms)
// if first time, set up the initial arrays with first set of data
if (!arr.length) {
return vals.map(v => [v])
}
// after first one, we will just loop over the arrays
// and start adding the next set of data to each one
return arr.reduce((updated, curr) => {
vals.forEach(val => {
// make copy so we are not adding data to the reference
const copy = curr.slice()
copy.push(val)
updated.push(copy)
})
return updated
}, [])
}, [])
console.log(JSON.stringify(out))
You could use recursion for this. Your input/output format is somewhat peculiar with its array-like objects, with keys starting at 1. So for that I would suggest a separate wrapper function, which only takes care of such format conversions.
I had a go at a functional approach, creating separate functions for each of the callbacks needed in the process:
const clone = o => ({...o});
const prefixer = item => arr => [item, ...arr].map(clone);
const merger = arr => item => arr.map(prefixer(item));
const extender = group => res => group.flatMap(merger(res));
// The recursive function based on standard array format
const cross = (group, ...rest) => group ? extender(group)(cross(...rest)) : [[]];
// For dealing with the unconventional input/output format:
const baseOne = (x, i) => [i+1, x];
const generatePermutations = obj =>
Object.fromEntries(cross(...Object.values(obj).map(Object.values)).map(baseOne));
// Sample data & call
const starterObject = {
id1: {
1: { value: "A" },
2: { value: "B" },
3: { value: "C" },
},
id2: {
1: { value: 10 },
2: { value: 20 },
},
};
const permutations = generatePermutations(starterObject);
console.log(permutations);

How to use ternary operator while pushing elements into the array

I am trying to add the objects into the array based on the condition.
My expectation is to add two objects when the condition met but I am getting only the last object getting added (its element is missing).
const country = ‘USA’
citizenArray.push([
{
label: ‘Alex’,
value: ’32’,
},
country === ‘USA’
? ({
label: ‘John’,
value: ’28’,
},
{
label: ‘Miller’,
value: ’40’,
})
: {
label: ‘Marsh’,
value: ’31’,
},
]);
The output I am getting:
[{
label: ‘Alex’,
value: ’32’,
},
{
label: ‘Miller’,
value: ’40’,
}]
Expected:
[{
label: ‘Alex’,
value: ’32’,
},
{
label: ‘John’,
value: ’28’,
},
{
label: ‘Miller’,
value: ’40’,
}]
Could somebody help me point out where I am doing wrong?
Thanks.
In Javascript when you placed comma-separated expressions within parathesis it will execute each(left to right) and will return the result of last.
In your case ({ label: 'John', value: '28',}, { label: 'Miller', value: '40',}) results just the last object { label: ‘Miller’, value: ’40’, } and adds to the array.
To make it work to use an array and then use spread syntax to add them.
const country = 'USA';
const citizenArray = [];
citizenArray.push([{
label: 'Alex',
value: '32',
},
...(country === 'USA' ? [{
label: 'John',
value: '28',
}, {
label: 'Miller',
value: '40',
}] : [{
label: 'Marsh',
value: '31',
}])
]);
console.log(citizenArray);
Just use different logic like so:
const country = "USA";
let citizenArray = [];
citizenArray.push([{ label: "Alex", value: "32" }, ...(country == "USA" ? [{ label: "John", value: "28" }, { label: "Miller", value: "40" }] : [{ label: "Marsh", value: "31" }])]);
console.log(citizenArray);
.as-console-wrapper { max-height: 100% !important; top: auto; }
How about using the Spread ... operator
const myArray = [
...(condition1 ? [item1] : []),
...(condition2 ? [item2] : []),
...(condition3 ? [item3] : []),
];

How to make morris donut chart with ajax json?

How to make morris donut chart with ajax json ?
this is my code :
$(function() {
$.ajax({
url : 'dashboard/total-data',
}).done(function(data){
initDonut(JSON.parse(data));
console.log(data);
}).fail(function(){
});
var initDonut = function(data){
return Morris.Donut({
element: 'morris-donut-chart',
data: [ data ],
// data: [
// {label: "BMW", value: 4},
// {label: "Mercy", value: 0},
// {label: "Ferrari", value: 0},
// {label: "Toyota", value: 3},
// {label: "Porsche", value: 0},
// {label: "Limosin", value: 0},
// {label: "Lamborgini", value: 3} ],
resize: true,
colors: ['#87d6c6', '#54cdb4','#1ab394', '#54cdb4','#1ab394', '#54cdb4','#1ab394'],
});
} });
Ajax code above return data format like this:
{"BMW":4,"Mercy":0,"Ferrari":0,"Toyota":3,"Porsche":0,"Limosin":0,"Lamborgini":3}
my question,
How to make format data above become like this with javascript?
[ {label: "BMW", value: 4},{label: "Mercy", value: 0},{label: "Ferrari", value: 0},{label: "Toyota", value: 3},{label: "Porsche", value: 0},{label: "Limosin", value: 0},{label: "Lamborgini", value: 3} ]
This is code for show json:
public function total_data()
{
$data['BMW'] = $this->m_dashboard->get_total_product_bmw();
$data['Mercy'] = $this->m_dashboard->get_total_product_mercy();
echo json_encode($data);
$data['Ferrari'] = $this->m_dashboard->get_total_product_ferrari();
$data['Toyota'] = $this->m_dashboard->get_total_product_toyota();
$data['Porsche'] = $this->m_dashboard->get_total_product_porsche();
$data['Limosin'] = $this->m_dashboard->get_total_product_limosin();
$data['Lamborgini'] = $this->m_dashboard->get_total_product_lamborgini();
echo json_encode($data);
}
You need to change code of total-data like below:-
public function total_data()
{
$data[0]['label']= 'BMW';
$data[0]['value']= $this->m_dashboard->get_total_product_bmw();
$data[1]['label']= 'Mercy';
$data[1]['value']= $this->m_dashboard->get_total_product_mercy();
$data[2]['label']= 'Ferrari';
$data[2]['value']= $this->m_dashboard->get_total_product_ferrari();
$data[3]['label']= 'Toyota';
$data[3]['value']= $this->m_dashboard->get_total_product_toyota();
$data[4]['label']= 'Porsche';
$data[4]['value']= $this->m_dashboard->get_total_product_porsche();
$data[5]['label']= 'Limosin';
$data[5]['value']= $this->m_dashboard->get_total_product_limosin();
$data[6]['label']= 'Lamborgini';
$data[6]['value']= $this->m_dashboard->get_total_product_lamborgini();
echo json_encode($data);
}
jQuery code need to be:-
$(function() {
$.ajax({
url : 'dashboard/total-data',
}).done(function(data){
Morris.Donut({
element: 'morris-donut-chart',
data: JSON.parse(data),
resize: true,
colors: ['#87d6c6', '#54cdb4','#1ab394', '#54cdb4','#1ab394', '#54cdb4','#1ab394']
});
}).fail(function(){
});
});
Working at my end:- http://prntscr.com/f6399z
It seems like the question is mostly, how do I get from
{key: foo, key2:bar}
to
[{label: key, value:foo},{label: key2, value:bar}]
I'm a huge fan of libraries like lodash and ramda. If you had Ramda available I would recommend something like:
var input = {
"BMW": 4,
"Mercy": 0,
"Ferrari": 0,
"Toyota": 3,
"Porsche": 0,
"Limosin": 0,
"Lamborgini": 3
}
var expected = [{
label: "BMW",
value: 4
}, {
label: "Mercy",
value: 0
}, {
label: "Ferrari",
value: 0
}, {
label: "Toyota",
value: 3
}, {
label: "Porsche",
value: 0
}, {
label: "Limosin",
value: 0
}, {
label: "Lamborgini",
value: 3
}]
// First thing we want is to group the key and value together
var pairs = R.toPairs(input);
// This gives us something like
// [["BMW",4],["Mercy",0],...]
// This is getting a little far to explain here but Ramda
// curries all it's functions so we can pass the labels
// here and then the pairs later.
var label = R.zipObj(["label", "value"]);
// Here we map the label function over each set of pairs
var output = pairs.map(label);
tape('Same?', t => {
t.deepEqual(expected, output);
t.end();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.min.js"></script>
<script src="https://wzrd.in/standalone/tape#latest"></script>
Otherwise, you could do something in a for loop.
var input = {
"BMW": 4,
"Mercy": 0,
"Ferrari": 0,
"Toyota": 3,
"Porsche": 0,
"Limosin": 0,
"Lamborgini": 3
}
var expected = [{
label: "BMW",
value: 4
}, {
label: "Mercy",
value: 0
}, {
label: "Ferrari",
value: 0
}, {
label: "Toyota",
value: 3
}, {
label: "Porsche",
value: 0
}, {
label: "Limosin",
value: 0
}, {
label: "Lamborgini",
value: 3
}]
var output = [];
for (var k in input) {
output.push({"label": k, "value": input[k]});
}
tape('Same?', t => {
t.deepEqual(expected, output);
t.end();
});
<script src="https://wzrd.in/standalone/tape#latest"></script>

Flatten 3D array containing objects to 2D removing duplicated objects by it's parameter

I have a 3D array with objects inside:
[
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
]
How to flatten it including removing duplicated id parameter?
[{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]
I think underscore would be helpful with that
var a = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
];
var flattened = _(a).flatten().uniq('id').value();
Of course you have to include lodash to your webpage.
You can use Underscore flatten and unique to accomplish this. However, whenever you are using multiple underscore operations, it is a good time to consider using the underscore chainging with chain and value:
var data = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
];
var result = _.chain(data)
.flatten()
.uniq(function(o) {
return o.id;
})
.value();
console.log('result', result);
JSFiddle: http://jsfiddle.net/0udLde0s/3/
Even shorter with current Underscore.js
If you use a recent version of Underscore.js (I tried current which is 1.8.3 right now), you can use .uniq('id') so it makes it even shorter:
var result = _.chain(data)
.flatten()
.uniq('id')
.value();
You can use _.flatten, and _.uniq, like so
var data = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
];
var result = _.uniq(_.flatten(data), function (el) {
return el.id;
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You don't need any library for this, it's quite simple:
function flatten(arr)
{
var map = {};
var flatArray = [];
function pushToMap(o) {
if(map[o.id])
return;
map[o.id] = true;
flatArray.push(o);
}
function arrRecurse(a) {
if(a.length === undefined)
pushToMap(a);
else {
a.forEach(function(i) {
arrRecurse(i);
});
}
}
arrRecurse(arr);
return flatArray;
}
var _3dArray = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
];
alert(JSON.stringify(flatten(_3dArray)));
No library, only native JS :
var ar = [
[{ id: 1 }, { id: 2 }],
[{ id: 3 }],
[{ id: 3 }, { id: 4 }]
];
//start
var output = [];
for (var x = 0, al = {}; x < ar.length; x++)
for (var y = 0, t = ar[x][y]; y < ar[x].length; y++, t = ar[x][y])
al[t.id] = (!al[t.id]) ? output.push(t) : 1;
//end
document.body.innerHTML += JSON.stringify(output);

Categories

Resources