Accessing nest elements by their keys with d3.js - javascript

So I have the following nest:
var myNest = [
{"key":"1","values":[...]},
{"key":"2","values":[...]},
{"key":"3","values":[...]},
]
How can I access these elements using their keys?
I know I can access them by their index
myNext[0] //return elements with key=="1"
myNest[1] //return elements with key=="2"
But what I would like to do is:
myNest["1"] //return elements with key=="1"
myNest["2"] //return elements with key=="2"
Thanks

Use map() instead of entries() when building your nest. You probably did something similar to this:
var products = [{
"id": 1,
"name": "Cat Hat",
"price": 49
}, {
"id": 2,
"name": "Unicorn Boots",
"price": 139
}, {
"id": 3,
"name": "Pink Woolly Jumper",
"price": 34
}];
var productsById = d3.nest()
.key(function(p) {
return p.id;
})
.entries(products);
console.log(productsById)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
If instead you use map():
var products = [{
"id": 1,
"name": "Cat Hat",
"price": 49
}, {
"id": 2,
"name": "Unicorn Boots",
"price": 139
}, {
"id": 3,
"name": "Pink Woolly Jumper",
"price": 34
}];
var productsById = d3.nest()
.key(function(p) {
return p.id;
})
.map(products);
console.log(productsById)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
You get a map where you can access objects by their key directly, e.g. with productsById["2"] in this example.

You could us a hash table, where the key of your object is the key for the object itselft.
For ES6 I suggest to use a Map:
var myNest = [{ key: "1", values: [1, 4] }, { key: "2", values: [2, 5] }, { key: "3", values: [3, 6] }],
hash = Object.create(null);
myNest.forEach(function (a) {
hash[a.key] = a;
});
console.log(hash['2']);

Related

How can I inner join with two object arrays in JavaScript?

I need inner join with two array in javascript like this:
array1 =
[
{
"id": 1,
"name": "Tufan"
},
{
"id": 2,
"name": "Batuhan"
},
{
"id": 3,
"name": "Hasan"
}
]
array2 =
[
{
"name": "yyy",
"externalid": "1",
"value": "Asd"
},
{
"name": "aaaa"
"externalid": "2",
"value": "ttt"
}
]
expectedArray =
[
{
"id": 1,
"name": "Tufan",
"externalid": "1",
"value": "Asd"
},
{
"id": 2,
"name": "Batuhan",
"externalid": "2",
"value": "ttt"
}
]
rules:
on: array2.externalid = array1.id
select: array1.id, array1.name, array2.externalid, array2.value
My approach:
array1.filter(e => array2.some(f => f.externalid == e.id));
// I need help for continue
How can I make this?
Doesn't matter information: I use ES5 and pure javascript
You can do it like this:
const res = array2.map((item) => {
const related = array1.find((el) => el.id == item.externalid);
return { ...item, ...related };
});
Using a map to loop over the array2 and a find to get the array1 relative.

copying data from one array to another array

Array One:
array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}]
Array Two:
array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}]
Resulting Array:
resultingArray = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}],
"a_id" : {"id": 5, "name": "bcd"}
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}],
"a_id" : {"id": 4, "name": "bef"}
}]
I am looking to add the array2 objects into array1 based on id's of array2. I have tried using map function on both the arrays to compare and add the object but I didn't succeed. Can you please suggest me how to do it?
Thank you
Add the array2 objects into array1 based on ids of array2.
let array1 =
[
{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}
];
let array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}
];
let resultingArray=[];
array1.forEach(function(element) {
element['a_id'] = [];
element['attr'].forEach(function(attr) {
element['a_id'].push(array2.find(function(item) {
return item.id == attr.value;
}));
});
resultingArray.push(element)
});
console.log(resultingArray);
I presume you intend to extract the object whose ID is equal to the value field the in the each object in array1.
var array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}];
var array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}];
var resultingArray = [];
for(var i = 0; i < array1.length; i++) {
resultingArray[i] = array1[i];
for(var j = 0; j < array2.length; j++) {
if(resultingArray[i].attr[0].attr_code.value === array2[j].id) {
resultingArray[i].push("a_id": array2[j]);
}
}
}
You just need to lop through array1, and for each object in array1, you need to find corresponding objects in array2 which match the criterion.
You can use array map and array index to do:
var array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}];
var array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}];
var result = array1.map(current=>{
//find index of attr in array2
let index = array2.findIndex(c=>{
if (c['id']===(Number(current['attr'][0]['value'])))
return c;
});
current["a_id"] = array2[index];
return current;
});
console.log(result);
Please check if the following code suites your requirement. You may need to make some changes.
function mergeArrays3 (arr1, arr2) {
return arr1.map((value, index) => {
let object = null;
let result = {...value};
for (let element of arr2) {
if (element.id == parseInt(value.attr[0].value)) {
object = element;
break;
}
}
if (object != null) {
let attr = value.attr[0];
if (attr.hasOwnProperty("attr")) {
result[value.attr[0].attr] = object;
} else if (attr.hasOwnProperty("attr_code")) {
result[value.attr[0].attr_code] = object;
}
}
return result;
});
}
I loop over first array and find an element in second array matching id of value.attr[0].value. If found then i added this object in the first array at key of value.attr[0].attr or value.attr[0].attr_code.
I have tried using map function on both the arrays to compare and add
the object but I didn't succeed
Below is the functional programming approach using map():
/* GIVEN */
const array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{
"attr_code": "a_id",
"value": "5"
}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{
"attr": "a_id",
"value": "4"
}]
}
]
const array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}]
/* From array2, make an object keyed by the 'id' field. We'll use this as a key-value lookup table */
const lookupTable = array2.reduce((accum, item) => {
accum[item.id.toString()] = item
return accum
}, {})
console.log('***LOOKUP TABLE***\n', lookupTable) // result is an object we use to lookup
/* From array1, we append data from the lookup table */
const final = array1.map(item => {
item.a_id = lookupTable[item.attr[0].value]
return item
})
console.log("***RESULT***\n", final)
Hope this helps.
Cheers,

Function that returns all the elements where field is 1

I have the array:
var tabs = [
{"id": 1, "Name": "Top", "Paris": 1, "London": 1, "Rome": 1},
{"id": 2, "Name": "Best", "Paris": 1, "London": 0, "Rome": 0},
{"id": 3, "Name": "Cheap", "Paris": 0, "London": 1, "Rome": 0}
];
How can I write a function that receives as argument one of the towns (London or Paris or Rome) different each time and returns the elements of the array which the argument is 1? For example, I want to take all the elements where London=1.
var tabs= [
{ "id": 1, "Name": "Top","Paris":1,"London":1, "Rome":1},
{ "id": 2, "Name": "Best","Paris":1,"London":0,"Rome":0},
{ "id": 3, "Name": "Cheap","Paris":0,"London":1,"Rome":0}
];
var getElementsWith=function(array,name){
var myElements=[];
array.forEach(function(tab){
if(tab[name]===1)
myElements.push(tab);
});
return myElements;
};
console.log(getElementsWith(tabs,"Paris"));
You can use Array.filter:
function filterList(cityName) {
return tabs.filter(function(o) {
return o[cityName] === 1;
});
}
You could use a generic function, which takes the array, key and value, you are looking for. Then use Array#filter for the sub set.
function filter(array, key, value) {
return array.filter(function (object) {
return object[key] === value;
});
}
var tabs = [{ "id": 1, "Name": "Top","Paris":1,"London":1, "Rome":1 },{ "id": 2, "Name": "Best","Paris":1,"London":0,"Rome":0 },{ "id": 3, "Name": "Cheap","Paris":0,"London":1,"Rome":0 }],
result = filter(tabs, 'London', 1);
console.log(result);

how do I create an array of objects with array in the object from an object with the same key in javascript

I have an array of objects that looks like this
[{
"name": "Agile Process",
"id": 27,
"score": 3,
"source": "Self"
},{
"name": "Agile Process",
"id": 27,
"score": 4,
"source": "Trainer"
},{
"name": "2 & 3 Tier Architecture",
"id": 37,
"score": 4,
"source": "Self"
},{
"name": "2 & 3 Tier Architecture",
"id": 37,
"score": 5,
"source": "Trainer"
}]
I want to be able to produce something like this, I have been trying hard but I do not seems to get a hang of it.
[
{
"name": "Agile Process",
"id": 7,
"data": [
{
"score": 3,
"source": "Self"
},{
"score": 4,
"source": "Trainer"
}
]
},
{
"name": "2 & 3 Tier Architecture",
"id": 37,
"data": [
{
"score": 4,
"source": "Self"
},{
"score": 5,
"source": "Trainer"
}]
}
];
How do I go about solving this problem?
One possible approach:
_.values(_.reduce(arr, function(acc, el) {
var id = el.id;
if (!acc.hasOwnProperty(id)) {
acc[id] = _.pick(el, 'id', 'name');
acc[id].data = [];
}
acc[id].data.push(_.pick(el, 'score', 'source'));
return acc;
}, {}));
Demo. It's a common method when you need to group things up.
Here's a pure javascript solution: use reduce method on the initial array using as the accumulator the result array (empty at first) which will store the transformed data. And as reduce method loops through the items of the initial array, check if the result array contains an element with id of the current item. If so, then just add new data to it, else create a new item in the result array.
var data = [{
"name": "Agile Process",
"id": 27,
"score": 3,
"source": "Self"
},{
"name": "Agile Process",
"id": 27,
"score": 4,
"source": "Trainer"
},{
"name": "2 & 3 Tier Architecture",
"id": 37,
"score": 4,
"source": "Self"
},{
"name": "2 & 3 Tier Architecture",
"id": 37,
"score": 5,
"source": "Trainer"
}];
var newData = [];
newData = data.reduce(function(acc, current) {
var existingArr = acc.filter(function(x) { return x.id === current.id });
if(existingArr.length === 0) {
acc.push({ name: current.name, id: current.id, data: [{ score: current.score, source: current.source }] });
}
else {
existingArr[0].data.push({ score: current.score, source: current.source });
}
return acc;
}, newData);
This version uses groupBy to group the items by id and then maps across each grouping to create the required object:
var groupToItem = function(items){
return {
id: items[0].id,
name: items[0].name,
data: _.map(items, function(item){
return _.pick(item, 'score', 'source');
})
}
}
var result = _.chain(data)
.groupBy('id')
.map(groupToItem)
.value();
Plain Javascript solution, only working for your specific data structure though:
function groupObjectsById(array){
var output = [];
var ids = [];
for(var i = 0; i < array.length; i++){
var current = array[i];
if(ids.indexOf(current.id) > -1){
var objInOutput = output.filter(function(obj){
if(obj.id === current.id){
return obj;
}
})[0];
var dataObj = { score: current.score, source: current.source};
objInOutput.data.push(dataObj);
}else{
var outputObject = {name: current.name, id: current.id};
outputObject.data = [{ score: current.score, source: current.source}];
output.push(outputObject);
ids.push(current.id);
}
}
return output;
}

Underscore.js : findWhere with nested property value

How do I go about the filtering below:
[{
"id": 100,
"title": "Tlt1",
"tax": [{
"name": "Tax1",
"id": 15
}, {
"name": "Tax1",
"id": 17
}]
}, {
"id": 101,
"title": "Tlt2",
"tax": [{
"name": "Tax2",
"id": 16
}]
}, {
"id": 102,
"title": "Tlt3",
"tax": [{
"name": "Tax3",
"id": 17
}, {
"name": "Tax3",
"id": 18
}]
}]
to get only those where tax.id is 17, as per below:
[
{
"id": 100,
"title": "Tlt1",
"tax": [
{
"name": "Tax1",
"id": 15
},
{
"name": "Tax1",
"id": 17
}
]
},
{
"id": 102,
"title": "Tlt3",
"tax": [
{
"name": "Tax3",
"id": 17
},
{
"name": "Tax3",
"id": 18
}
]
}
]
Currently I use the method below, but maybe there is more clean way of going about this?
var arr = [];
_(data).each(function (v1, k1) {
_(v1.tax).each(function (v2, k2) {
if (v2.id == id) {
arr.push(v1);
}
});
});
Demo here: http://jsfiddle.net/7gcCz/2/
Any suggestion much appreciated.
You may use the combination of _.filter and _.where
_.filter(data, function(obj) {
return _.where(obj.tax, {id: ID_TO_FIND}).length > 0;
})
See demo: http://jsfiddle.net/hCVxp/
Update
Thanks to #GruffBunny. A more efficient way is to use _.some to avoid looping through all tax items:
var arr = _.filter(data, function(obj) {
return _.some(obj.tax, {id: ID_TO_FIND});
});
See demo: http://jsbin.com/putefarade/1/edit?html,js,console
Use _.filter to find candidate items and _.some to check for the existence of an item in a collection:
var filteredList = _.filter(list, function(item){
return _.some(item.tax, { id: 17 });
});
You can do this with _.where alone.
var filteredList = _.where(list, { tax:[{id:17}] });
Edit: This method works in older version of lodash, but wont work in current underscore or lodash.
Working example anyway:
https://jsfiddle.net/rhp4crma/

Categories

Resources