I have an array:
var array = {
"mylist": [
{
"item1": "The Ba",
"id": 1
},
{
"item1": "Hurts Ama",
"id": 2
}
]
}
and to sort them I am using the following function:
function sortByItem(a,b) {
if (a.item1 < b.item1)
return -1;
if (a.item1 > b.item1)
return 1;
return 0;
}
which gives me the output
[Hurts Ama, The Ba]
However, I don't want "The" to be included when comparing, so that the output would actually be:
[Ba, Hurts Ama]
You could replace the at the beginning with following whitespace.
var array = [{ item1: "The Ba", id: 1 }, { item1: "Hurts Ama", id: 2 }, { item1: "Thereafter ", id: 3 }];
array.sort(function (a, b) {
function getStripped(s) { return s.replace(/^the\s+/i, ''); }
return getStripped(a.item1).localeCompare(getStripped(b.item1));
});
console.log(array)
.as-console-wrapper { max-height: 100% !important; top: 0; }
first map a transform function every of your objects that removes any "The " then run your sort by
function transform(item) {
return {
id: item.id,
item: item.replace("The ","")
}
}
var list =
[
{
"item": "The Ba",
"id": 1
},
{
"item": "Hurts Ama",
"id": 2
}
]
list.map(transform).sort(sortByItem)
Related
I am trying to do an opposite of flattening an array.
I have the following input JSON array of 4 elements:
[
{
"nestedObj": {
"id":12
}
},
{
"nestedObj": {
"id":555
}
},
{
"nestedObj": {
"id":555
}
},
{
"nestedObj" :{
"id":771
}
}
]
I want to transform it to an array of arrays, where each subarray has elements of the same nestedObj.id grouped up together.
I can assume the initial JSON is sorted by nestedObj.id.
In the above example, the id of nestedObj of 2nd and 3rd element are the same (555), so those elements would be grouped into one sub-array.
This would be the result, an array of only 3 sub-array elements:
[
[{
"nestedObj": {
"id":12
}
}],
[{
"nestedObj": {
"id":555
}
},
{
"nestedObj": {
"id":555
}
}],
[{
"nestedObj" :{
"id":771
}
}]
]
And this is the code that gets me what I want:
const data = [ /* ...the above input data... */ ];
let result = [];
let prevId = null;
for (let elem of data) {
let currId = elem.nestedObj.id;
if (currId === prevId) {
result[result.length - 1].push({...elem});
} else {
result.push([{...elem}]);
}
prevId = currId;
}
But as you can see... the code is very declarative. It's not very JavaScript-like, in a functional programming sense.
How can I re-write it using e.g. reduce or other 'modern JS' techniques?
Just group the objects.
let array = [{ nestedObj: { id: 12 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 771 } }],
result = Object.values(array.reduce((r, o) => {
(r[o.nestedObj.id] = r[o.nestedObj.id] || []).push(o);
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can group by id using the function reduce, extract the grouped values using the function Object.values, and finally map the array to build the desired output.
This is assuming we have only one attribute called nestedObj
let arr = [{ nestedObj: { id: 12 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 771 } }],
result = Object.values(arr.reduce((a, {nestedObj: {id}}) => {
(a[id] || (a[id] = [])).push(id);
return a;
}, {})).map(r => r.map(id => ({nestedObj: {id}})));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use a Map to group the items with same id then get the final values from the Map
const data = [{ nestedObj: { id: 12 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 555 } }, { nestedObj: { id: 771 } }]
const map = new Map;
data.forEach(o => {
const {nestedObj:{id}} = o;
map.has(id) ? map.get(id).push(o) : map.set(id,[o]);
});
console.log([...map.values()])
Is it possible to rearrange the below JSON format based on time (2016-12-07T13:00:00) using jQuery/Javascript.
[
{
"id":1,
"start":"2016-12-07T13:00:00",
"subject":"test1",
},
{
"id":2,
"start":"2016-12-07T09:00:00",
"subject":"test2",
},
{
"id":3,
"start":"2016-12-07T10:00:00",
"subject":"test3",
},
{
"id":4,
"start":"2016-12-07T07:00:00",
"subject":"test4",
},
{
"id":5,
"start":"2016-12-07T14:00:00",
"subject":"test5",
}
]
You could use String#localeCompare in a sort callback for the property start, because ISO 8601 dates are sortable as string.
var array = [
{ id: 1, start: "2016-12-07T13:00:00", subject: "test1" },
{ id: 2, start: "2016-12-07T09:00:00", subject: "test2" },
{ id: 3, start: "2016-12-07T10:00:00", subject: "test3" },
{ id: 4, start: "2016-12-07T07:00:00", subject: "test4" },
{ id: 5, start: "2016-12-07T14:00:00", subject: "test5" }
];
array.sort(function (a, b) {
return a.start.localeCompare(b.start);
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
//put to variable
var db = [
{
"id":1,
"start":"2016-12-07T13:00:00",
"subject":"test1",
},
{
"id":2,
"start":"2016-12-07T09:00:00",
"subject":"test2",
},
{
"id":3,
"start":"2016-12-07T10:00:00",
"subject":"test3",
},
{
"id":4,
"start":"2016-12-07T07:00:00",
"subject":"test4",
},
{
"id":5,
"start":"2016-12-07T14:00:00",
"subject":"test5",
}
];
//use .sort()
db.sort(
function(a,b){
//use new Date parse string to date type
//convert date to number use Date.parse()
//format function(a,b) { return a-b; }
return Date.parse(new Date(a.start)) - Date.parse(new Date(b.start));
}
);
console.log(db)
If You can use External Library For example Lodash
https://lodash.com/
Assign the json string to variable and try
var sort = _.sortBy(variable_name, "start")
hope this Helps you.
Yes, you would use the javascript array sort method ( http://www.w3schools.com/jsref/jsref_sort.asp ).
Define your array as assign it to an variable then call the sort method, you can pass the sort method a function to perform the detail of the comparison.
var aryData = [{"id":1
,"start":"2016-12-07T13:00:00"
,"subject":"test1"
},{
"id":2
,"start":"2016-12-07T09:00:00"
,"subject":"test2"
},{
"id":3
,"start":"2016-12-07T10:00:00"
,"subject":"test3"
},{
"id":4
,"start":"2016-12-07T07:00:00"
,"subject":"test4"
},{
"id":5
,"start":"2016-12-07T14:00:00"
,"subject":"test5"
}];
aryData.sort(function(a, b) {
var dtA = new Date(a['start'])
,dtB = new Date(b['start']);
return ( dtA.getTime() - dtB.getTime() );
});
Try this maybe helpful,
var aryData =[
{
"id":1,
"start":"2016-12-07T13:00:00",
"subject":"test1",
},
{
"id":2,
"start":"2016-12-07T09:00:00",
"subject":"test2",
},
{
"id":3,
"start":"2016-12-07T10:00:00",
"subject":"test3",
},
{
"id":4,
"start":"2016-12-07T07:00:00",
"subject":"test4",
},
{
"id":5,
"start":"2016-12-07T14:00:00",
"subject":"test5",
}
];
function comp(a, b) {
return new Date(a.start).getTime() - new Date(b.start).getTime();
}
aryData.sort(comp);
console.log(aryData);
Input :
"options": [
{
"name": "Color",
"values": [
"Blue",
"Black"
]
},
{
"name": "Size",
"values": [
"Small",
"Large"
]
}
]
Output: "variants": [
{
"option1": "Blue",
"option2": "Small"
},
{
"option1": "Blue",
"option2": "Large"
},
{
"option1": "Black",
"option2": "Small"
},
{
"option1": "Black",
"option2": "Large"
}
]
How to solve this using recursion ?The options array can contain multiple name and i need the above out to be displayed. Can it be done using cartesian product i guess
You could take an iterative and recursive approach for getting all option combinations.
function getCombinations(array) {
function iter(i, temp) {
if (i === array.length) {
result.push(temp.reduce(function (o, v, i) {
o['option' + (i + 1)] = v;
return o;
}, {}));
return;
}
array[i].values.forEach(function (a) {
iter(i + 1, temp.concat(a));
});
}
var result = [];
iter(0, []);
return result;
}
var options = [{ name: "Color", values: ["Blue", "Black"] }, { name: "Size", values: ["155", "159"] }, { name: 'Material', values: ['Sand', 'Clay', 'Mud'] }],
variants = getCombinations(options);
console.log(variants);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6
function getCombinations(array) {
function iter(i, temp) {
if (i === array.length) {
result.push(temp);
return;
}
array[i].values.forEach(a => iter(i + 1, Object.assign({}, temp, { ['option' + (i + 1)]: a })));
}
var result = [];
iter(0, {});
return result;
}
var options = [{ name: "Color", values: ["Blue", "Black"] }, { name: "Size", values: ["155", "159"] }, { name: 'Material', values: ['Sand', 'Clay', 'Mud'] }],
variants = getCombinations(options);
console.log(variants);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use nested Array.map() calls, create the objects, and flatten the sub arrays using Array.concat():
const options = [{"name":"Color","values":["Blue","Black"]},{"name":"Size","values":["155","159"]}]
const [{ values: colors }, { values: sizes }] = options
const result = [].concat(...colors.map((option1) => sizes.map((option2) => ({
option1,
option2
}))))
console.log(result)
var myarray = {"options": [
{
"name": "Color",
"values": [
"Blue",
"Black"
]
},
{
"name": "Size",
"values": [
"155",
"159"
]
}
]};
const key = myarray.options[0].values;
const value =myarray.options[1].values;
const output = _.zipWith(key, value, (key, value)=> ({ key, value }));
console.log(output);
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>
Good Day People
I have an array of objects and I need to print out the path of each node value and last print key and value for special (by name) node.
This is the array of objects or JSON
[{
"Name": "2007",
"Elements": [{
"Name": "country1",
"Elements": [{
"House": "house1",
"water": 1.8
}],
"Data": {}
},
{
"Name": "country2",
"Elements": [{
"Name": "city2",
"Elements": [{
"Name": "neighbourhood2",
"Elements": [{
"House": "house2",
"water": 2.8
}]
}],
"Data": {}
}],
"Data": {}
},
{
"Name": "country3",
"Elements": [{
"House": "house2",
"uni bill": 3.8
}],
"Data": {}
}
],
"Data": {}
}]
The output should be like this
2007 > country1 > house > water: 1.8
2007 > city2 > neighbourhood2 > house2 > electricity: 2.8
2007 > country3 > house > uni bill: 3.8
++++++++++++++ edited +++++++++++++++
function objectToPaths(data) {
var validId = /^[a-z_$][a-z0-9_$]*$/i;
var result = [];
doIt(data, "");
return result;
function doIt(data, s) {
if (data && typeof data === "object") {
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
doIt(data[i], s + "");
}
} else {
for (var p in data) {
if (validId.test(p)) {
doIt(data[p], s + " > " + data[p]);
} else {
doIt(data[p], s + "");
}
}
}
} else {
result.push(s);
}
}
}
this is a rewrite of a function I found here but I did not get the expected result
+++++++++++++++++++++++ end of the edit +++++++++++++++++++++++
Please help
Thanks in advance
What you are looking for is a Depth First Traversal function that recursively print properties:
function print(arr, path) { // print takes an array an an accumulated path from which it will start printing
arr.forEach(function(obj) { // for each object obj in the array
if(obj.Elements) { // if the object obj has sub elements in it
print(obj.Elements, path + " > " + obj.Name); // then call print on those elements, providin the absolute path to this object
} else { // otherwise (it is a leaf)
const bills = Object.keys(obj)
.filter(key => key !== "House")
.map(key => `${key}: ${obj[key]}`)
.join(', ')
console.log(path.slice(3) + " > " + obj.House + " > " + bills); // print the accumulated path along with the House property of this object (removing the first 3 letters from path which are equal to " > ")
}
});
};
var arr = [{"Name":"2007","Elements":[{"Name":"country1","Elements":[{"House":"house1","water":1.8}],"Data":{}},{"Name":"country2","Elements":[{"Name":"city2","Elements":[{"Name":"neighbourhood2","Elements":[{"House":"house2","water":2.8}]}],"Data":{}}],"Data":{}},{"Name":"country3","Elements":[{"House":"house2","uni bill":3.8}],"Data":{}}],"Data":{}}];
print(arr, "");
You could take a function for iterating and collect the path to the last object.
function iter(array, path) {
path = path || [];
array.forEach(function (o) {
if (o.Elements) {
return iter(o.Elements, path.concat(o.Name));
}
Object.keys(o).forEach(function (k) {
if (k !== 'House') {
console.log(path.concat(o.House, k).join(' > ') + ': ' + o[k]);
}
});
});
}
var data = [{ Name: "2007", Elements: [{ Name: "country1", Elements: [{ House: "house1", water: 1.8 }], Data: {} }, { Name: "country2", Elements: [{ Name: "city2", Elements: [{ Name: "neighbourhood2", Elements: [{ House: "house2", water: 2.8 }] }], Data: {} }], Data: {} }, { Name: "country3", Elements: [{ House: "house2", "uni bill": 3.8 }], Data: {} }], Data: {} }];
iter(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Going through the link Merge/flatten an array of arrays in JavaScript? is somewhat what i need. But with that link and many other links shows merging of arrays of two arrays. What I have is as follows
[
{
"setter":[
{
"keyname":"Sample Size",
"cond":"=",
"value":1
}
]
},
{
"setter":[
{
"joinedcond":"and"
},
{
"keyname":"Sample Size",
"cond":"=",
"value":2
}
]
}
]
That is I have an array and inside that array I have an array "setter".
What I want is actually merging all setter array as a single array. Having said the merge should produce below output
[
{
"setter":[
{
"keyname":"Sample Size",
"cond":"=",
"value":1
},
{
"joinedcond":"and"
},
{
"keyname":"Sample Size",
"cond":"=",
"value":2
}
]
}
]
Help would be appreciated. Thanks
You can do it by using Array#reduce
var arr = [{"setter":[{"keyname":"Sample Size","cond":"=","value":1}]},{"setter":[{"joinedcond":"and"},{"keyname":"Sample Size","cond":"=","value":2}]}];
var finalArr = arr.reduce((a,x)=>{
(a[0].setter = a[0].setter || []).push(...x.setter);
return a;
},[{}]);
console.log(finalArr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use a hash table for the outer keys and concat the inner values with a dynamic approach for the outer keys, like setter.
var data = [{ setter: [{ keyname: "Sample Size", cond: "=", value: 1 }] }, { setter: [{ joinedcond: "and" }, { keyname: "Sample Size", cond: "=", value: 2 }] }],
result = data.reduce(function (hash) {
return function (r, o) {
Object.keys(o).forEach(function (k) {
if (!hash[k]) {
hash[k] = {};
r.push(hash[k]);
}
hash[k][k] = (hash[k][k] || []).concat(o[k]);
});
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using ES6 Rest and Spread operators we can achieve the same with a recursive function call:
let cdata= data.slice();//Copy the data
let condensedArray=[];
function flatten(data, ...rest){
let [{ setter }] = data;
condensedArray = [...condensedArray, ...setter];
data.splice(0,1);
data.length>0?flatten(data, ...data):console.log('Complete');
}
flatten(cdata, ...cdata);
console.log(condensedArray);