getting distinct values from array of arrays in Javascript - javascript

My data is in the following format..
var data= [['typeName', 'valueName'], ['type1', 'value1'],
['type1', 'value2'],['type2', 'value3'],['type2', 'value4']]
I wish to transform the above data to data as below..
var resultdata=[{'typeName':'type1','valueName':['value1','value2']},
{'typeName':'type2','valueName':['value3','value4']}]
Basically I pick up distinct 'typeName' values and then group 'valueName' values by 'typeName' values.
I would preferably use only knockoutjs, lodash or underscorejs as my soln already uses them but I'm open to other solutions as well..
All help is sincerely appreciated
Thanks

I think this solution using underscore should do the trick:
var result= _.chain(data)
.rest()
.groupBy( value => value[0])
.map( (value,key) => ({ [data[0][0]]: key, [data[0][1]]: _.map(value, val => val[1])}))
.value();
This solution uses rest to skip the first item in the data array (the type descriptors). The array is then grouped by the first value in the array (the type) and the mapping returns the grouping in the required form using es6 object initializer notation.

Given the result as:
var resultdata=[
{'typeName':'type1'},{'valueName':['value1','value2']},
{'typeName':'type2'},{'valueName':['value3','value4']}
]
I'm going to call 'typeName' the category and 'valueName' the items.
Since the original data look like this:
var data= [
['typeName', 'valueName'],
['type1', 'value1'],
['type1', 'value2'],
['type2', 'value3'],
['type2', 'value4']
]
It is clear there is a pattern. The first row of data is what we'll use as labels for category and items. All the remaining data represent the values being used inside category and items.
The first step is to extract the labels:
var categoryLabel = data[0][0];
var itemLabel = data[0][1];
Next, the unique categories will need to be determined, so we'll use reduce to build an array of unique categories:
var categories = data
.filter(function(row, i) { return i > 0 }) // remove the labels
.reduce(function(arrCategories, currRow) {
// Add the current rows' category if it doesn't already exist
var currCategory = currRow[0];
if (arrCategories.indexOf(currCategory) === -1) {
return arrCategories.concat(currCategory);
}
return arrCategories;
}, [])
Now that you have a set of categories, you just need to iterate over each one to find all items that belong to it:
var valuesByCategory = {};
categories.forEach(function(category) {
// find all the data items that match the category
var items = data
.filter(function(row) { return row[0] === category; })
.reduce(function(arrItems, currRow) {
var currItem = currRow[1];
if (arrItems.indexOf(currItem) === -1) {
return arrItems.concat(currItem);
}
return arrItems;
}, []);
valuesByCategory[category] = items;
});
Now that all the data has been parsed out, the only thing left to do is build the resultant array:
var resultdata = [];
// iterate through each of the categories
categories.forEach(function(category) {
// using the category label, output an object with the label and category
var categoryObj = {};
categoryObj[categoryLabel] = category;
resultdata.push(categoryObj);
// Next, create a items object containing all the values
var itemsObj = {};
itemsObj[itemLabel] = valuesByCategory[category];
resultdata.push(itemsObj);
}
and that's it :)
The best part is that you don't need any external libraries. This is all ES2015 javascript!

Here is a lodash version of Gruff Bunnies solution:
var data= [['typeName', 'valueName'], ['type1', 'value1'], ['type1', 'value2'],['type2', 'value3'],['type2', 'value4']]
var names = data[0]
var values = _.tail(data)
console.log(JSON.stringify(
_(values)
.groupBy(0)
.map( (value, key) => ({ [names[0]]: key, [names[1]]: _.map(value, 1)}) )
.value()
))
https://jsfiddle.net/nmf1fdf5/

Related

Merge and create an unique case sensitive array in javascript

It's a complicated scenario but will try to explain as much as possible. I have one object or arrays and one array. Now i have to compare selectedmodel values with mappedmodels, if the value(Case insensitive) matches with that object then fetch all the values of it and push it into selected model and combine both. Hope the example will clear what i am trying to achive.
var mappedModels = { 'CC605': ['cc605', 'CC605', 'cC605'], 'TC75X': ['TC75X'] };
var selectedModels = ['CC605', 'tc76'];
var desiredOutput = ["CC605", "tc76", "cc605", "cC605"];
I already wrote a solution to achieve it but i need a better code in terms of performance. Here is the solution:
function combineModelCases(selectedModels) {
const modelCases = [];
selectedModels.forEach(elm => {
const existingModels = mappedModels[elm.toUpperCase()];
if (existingModels) {
for (const key of existingModels) {
if (elm.toUpperCase() !== key) {
modelCases.push(key);
}
}
}
});
return selectedModels.concat(modelCases);
}
Here is Fiddle
I am using typescript and underscore js for your references. Any help would be very helpful.
You could use flatMap to get a flattened array of values for each key in selectedModels. Then, create a Set to get a unique collection models. Use Array.from() to convert the set to an array.
const mappedModels = { 'CC605': ['cc605', 'CC605', 'cC605'], 'TC75X': ['TC75X'] },
selectedModels = ['CC605', 'tc76'];
const models = selectedModels.flatMap(m => mappedModels[m] || []),
unique = Array.from(new Set([...selectedModels, ...models]));
console.log(unique)
you can do the following, :
var mappedModels = { 'CC605': ['cc605', 'CC605', 'cC605'], 'TC75X': ['TC75X'] };
var selectedModels = ['CC605', 'tc76'];
var desiredOutput;
function combineModelCases(selectedValue){
if(mappedModels.hasOwnProperty(selectedValue)){
desiredOutput = [... new Set([...mappedModels[selectedValue], ...selectedModels])]
return desiredOutput;
}
}
console.log(combineModelCases('CC605'));
here is the working demo : https://jsfiddle.net/wzo4d6uy/2/:

Javascript String splitting and Organizing based on first letter

I am currently working a project that I have to use js and php to retrieve data from the gateway. Now that i have retrieved it, but the data is not organised:
{"timestamp":1526524809413,"data":[
{"_id":"rJeixnNtpG","data":"N11B00074","raw":
[78,49,49,66,48,48,48,55,52],"timestamp":1525398515116},
{"_id":"HkzognEYpf","data":"N11E00000","raw":
[78,49,49,69,48,48,48,48,48],"timestamp":1525398515479},
{"_id":"BJxXp4t6M","data":"N11A00029","raw":
[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}
As you can see there are three types of data: the one starts with B(N11B00074), E(N11E00000) and A(N11A00029), followed by the 5 digits which is the data i wanted to split from the string while categorised by the type(B, E and A).
I have three tables in my web page and want to put the data into them based on the types: Like B being humidity table, A being temperature table and E being pH readings table.
So far i only managed to list them out in a table.
Is there a way that I can seperate the string and put them into an array based on their types?
You can use reduce to group objects in an array:
const input={"timestamp":1526524809413,"data":[{"_id":"rJeixnNtpG","data":"N11B00074","raw":[78,49,49,66,48,48,48,55,52],"timestamp":1525398515116},{"_id":"HkzognEYpf","data":"N11E00000","raw":[78,49,49,69,48,48,48,48,48],"timestamp":1525398515479},{"_id":"BJxXp4t6M","data":"N11A00029","raw":[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}]}
const arranged = input.data.reduce((accum, obj) => {
const { data } = obj;
const type = data[3];
const digits = data.slice(5);
if (!accum[type]) accum[type] = [];
accum[type].push({ ...obj, digits });
return accum;
}, {});
console.log(arranged);
// If you want an array and not an object:
console.log(Object.values(arranged));
If you want to group the array into an object. You can use reduce. You can get the fourth character of the string by using charAt
let arr = {"timestamp":1526524809413,"data":[{"_id":"rJeixnNtpG","data":"N11B00074","raw": [78,49,49,66,48,48,48,55,52],"timestamp":1525398515116}, {"_id":"HkzognEYpf","data":"N11E00000","raw": [78,49,49,69,48,48,48,48,48],"timestamp":1525398515479}, {"_id":"BJxXp4t6M","data":"N11A00029","raw":[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}]};
let result = arr.data.reduce((c, v) => {
let l = v.data.charAt(3); //Get the 4th chatacter
c[l] = c[l] || [];
c[l].push(v);
return c;
}, {});
console.log( result );

Dynamically create array of objects, from array of objects, sorted by an object property

I'm trying to match and group objects, based on a property on each object, and put them in their own array that I can use to sort later for some selection criteria. The sort method isn't an option for me, because I need to sort for 4 different values of the property.
How can I dynamically create separate arrays for the objects who have a matching property?
For example, I can do this if I know that the form.RatingNumber will be 1, 2, 3, or 4:
var ratingNumOne = [],
ratingNumTwo,
ratingNumThree,
ratingNumFour;
forms.forEach(function(form) {
if (form.RatingNumber === 1){
ratingNumOne.push(form);
} else if (form.RatingNumber === 2){
ratingNumTwo.push(form)
} //and so on...
});
The problem is that the form.RatingNumber property could be any number, so hard-coding 1,2,3,4 will not work.
How can I group the forms dynamically, by each RatingNumber?
try to use reduce function, something like this:
forms.reduce((result, form) => {
result[form.RatingNumber] = result[form.RatingNumber] || []
result[form.RatingNumber].push(form)
}
,{})
the result would be object, with each of the keys is the rating number and the values is the forms with this rating number.
that would be dynamic for any count of rating number
You could use an object and take form.RatingNumber as key.
If you have zero based values without gaps, you could use an array instead of an object.
var ratingNumOne = [],
ratingNumTwo = [],
ratingNumThree = [],
ratingNumFour = [],
ratings = { 1: ratingNumOne, 2: ratingNumTwo, 3: ratingNumThree, 4: ratingNumFour };
// usage
ratings[form.RatingNumber].push(form);
try this its a work arround:
forms.forEach(form => {
if (!window['ratingNumber' + form.RatingNumber]) window['ratingNumber' + form.RatingNumber] = [];
window['ratingNumber' + form.RatingNumber].push(form);
});
this will create the variables automaticly. In the end it will look like this:
ratingNumber1 = [form, form, form];
ratingNumber2 = [form, form];
ratingNumber100 = [form];
but to notice ratingNumber3 (for example) could also be undefined.
Just to have it said, your solution makes no sense but this version works at least.
It does not matter what numbers you are getting with RatingNumber, just use it as index. The result will be an object with the RatingNumber as indexes and an array of object that have that RatingNumber as value.
//example input
var forms = [{RatingNumber:5 }, {RatingNumber:6}, {RatingNumber:78}, {RatingNumber:6}];
var results = {};
$.each(forms, function(i, form){
if(!results[form.RatingNumber])
results[form.RatingNumber]=[];
results[form.RatingNumber].push(form);
});
console.log(results);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HIH
// Example input data
let forms = [{RatingNumber: 1}, {RatingNumber: 4}, {RatingNumber: 2}, {RatingNumber: 1}],
result = [];
forms.forEach(form => {
result[form.RatingNumber]
? result[form.RatingNumber].push(form)
: result[form.RatingNumber] = [form];
});
// Now `result` have all information. Next can do something else..
let getResult = index => {
let res = result[index] || [];
// Write your code here. For example VVVVV
console.log(`Rating ${index}: ${res.length} count`)
console.log(res)
}
getResult(1)
getResult(2)
getResult(3)
getResult(4)
Try to create an object with the "RatingNumber" as property:
rating = {};
forms.forEach(function(form) {
if( !rating[form.RatingNumber] ){
rating[form.RatingNumber] = []
}
rating[form.RatingNumber].push( form )
})

Create an array of Objects from JSON

I have a JSON file like below:
[
{"fields":{category_class":"CAT2",category_name":"A"},"pk":1 },
{"fields":{category_class":"CAT1",category_name":"B"},"pk":2 },
{"fields":{category_class":"CAT1",category_name":"C"},"pk":3 },
{"fields":{category_class":"CAT2",category_name":"D"},"pk":4 },
{"fields":{category_class":"CAT3",category_name":"E"},"pk":5 },
{"fields":{category_class":"CAT1",category_name":"E"},"pk":6 },
]
I want to create an array of objects from the above JSON which will have two properties. i) CategoryClass ii) CategoryNameList. For example:
this.CategoryClass = "CAT1"
this.CategoryNameList = ['B','C','E']
Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class. I tried this:
var category = function(categoryClass, categoryNameList){
this.categoryClass = categoryClass;
this.categoryList = categoryNameList;
}
var categories = [];
categories.push(new category('CAT1',['B','C','E'])
Need help.
You can use a simple filter on the array. You have a few double quotes that will cause an error in you code. But to filter only with CAT1 you can use the filter method
var cat1 = arr.filter( value => value.fields.category_class === "CAT1");
I would suggest this ES6 function, which creates an object keyed by category classes, providing the object with category names for each:
function groupByClass(data) {
return data.reduce( (acc, { fields } ) => {
(acc[fields.category_class] = acc[fields.category_class] || {
categoryClass: fields.category_class,
categoryNameList: []
}).categoryNameList.push(fields.category_name);
return acc;
}, {} );
}
// Sample data
var data = [
{"fields":{"category_class":"CAT2","category_name":"A"},"pk":1 },
{"fields":{"category_class":"CAT1","category_name":"B"},"pk":2 },
{"fields":{"category_class":"CAT1","category_name":"C"},"pk":3 },
{"fields":{"category_class":"CAT2","category_name":"D"},"pk":4 },
{"fields":{"category_class":"CAT3","category_name":"E"},"pk":5 },
{"fields":{"category_class":"CAT1","category_name":"E"},"pk":6 },
];
// Convert
var result = groupByClass(data);
// Outut
console.log(result);
// Example look-up:
console.log(result['CAT1']);
Question : Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class
Solution :
function Select_CatName(catclass,array){
var CatNameList=[]
$(array).each(function(){
if(this.fields.category_class==catclass)
CatNameList.push(this.fields.category_name)
})
return CatNameList;
}
This function return the Desired Category Name List, you need to pass desired catclass and array of the data , as in this case it's your JSON.
Input :
Above function calling :
Output :
Hope It helps.

Filter properties from an array based on another array

I have an array of objects like this:
var bridges = {"countyCd:15
createdDate:"0001-01-01T00:00:00"
createdUserId:0
createdUserIdZ:null
createdUserName:null
description:"SR 1#.-CENTRAL RR COMP OF IND"
districtId:null
encryptedId1:null
encryptedId2:null
isDirty:false
modelState:null
nbiNumber:10
routeNbr:"1"
routeTypeCd:"SR"
transactionType:null
updatedDate:"0001-01-01T00:00:00"
updatedUserId:0
updatedUserIdZ:null
updatedUserName:null", [...]....}
I have another array like this
[countyCd, nbiNumber]
How can create another array keeping just two properties so it becomes like
bridges = {"countyCd:15
nbiNumber:10"
, [...]....}
Basically, I am looking for a way to create a function that takes a data array and a filter array as parameters and filters the data array based on the filter array.
Any pointers to this will be much appreciated.
One solution would be to map over each record and reduce your filter array into an object containing the target proprties:
var bridges = [{
countyCd:15,
createdDate:"0001-01-01T00:00:00",
createdUserId:0,
createdUserIdZ:null,
createdUserName:null,
description:"SR 1#.-CENTRAL RR COMP OF IND",
districtId:null,
encryptedId1:null,
encryptedId2:null,
isDirty:false,
modelState:null,
nbiNumber:10,
routeNbr:"1",
routeTypeCd:"SR",
transactionType:null,
updatedDate:"0001-01-01T00:00:00",
updatedUserId:0,
updatedUserIdZ:null,
updatedUserName:null
}, {
countyCd:23,
createdDate:"0001-01-01T00:00:00",
createdUserId:0,
createdUserIdZ:null,
createdUserName:null,
description:"SR 1#.-CENTRAL RR COMP OF IND",
districtId:null,
encryptedId1:null,
encryptedId2:null,
isDirty:false,
modelState:null,
nbiNumber:10,
routeNbr:"1",
routeTypeCd:"SR",
transactionType:null,
updatedDate:"0001-01-01T00:00:00",
updatedUserId:0,
updatedUserIdZ:null,
updatedUserName:null
}];
var filters = ['countyCd', 'nbiNumber'];
var transformedRecords = bridges.map(bridge => filters.reduce((p, c) => {
p[c] = bridge[c];
return p;
}, {}));
console.log(transformedRecords);
Say you have an array of bridges, call it bA:
var bA = []; //bridges array
var nbiA = []; // nbia array with countyCd
var newA = []; // new array
bA.forEach(function(element, index, array){
var newEntry = {
'countyCd':element.countyCd,
'nbiNumber':nbiA.find(function(nbi){
return nbi[countyCd] == element.countyCd;
}).nbiNumber
};
newA.push(newEntry);
});
//do whatever you want with the newA array

Categories