After I request some data with an API call, I want to sort this data. The call returns the following structure:
var values =[
{id: 1, type: "Gas", name: "G1,6", contractedPower: "2.5"},
{id: 2, type: "Gas", name: "G10", contractedPower: "2.5"},
{id: 3, type: "Gas", name: "G2,6", contractedPower: "2.5"},
{id: 4, type: "Gas", name: "G100", contractedPower: "2.5"},
{id: 5, type: "Electricity", name: "1X4A", contractedPower: "0.8"},
{id: 6, type: "Electricity", name: "1X6A", contractedPower: "0.8"},
{id: 7, type: "Electricity", name: "1X10A", contractedPower: "0.8"}, ....]
I've tried sorting it using the following algorithm:
var PhysicalCapacities = [];
for (var i = 0; i < values.length; i++){
if (values[i].type == type){
PhysicalCapacities.push(values[i]);
}
}
var sortedArray = _(PhysicalCapacities).chain().sortBy(function(PhysicalCapacity) {
return PhysicalCapacity.name;}).value();
This algorithm first filters out the ones with the right type. Then, it sorts it by the name value. The only problem is, it sorts them in a semi-right order:
For gas:
G1,6, G10, G100, G2,6
While it should be:
G1,6, G2,6, G10, G100
And for electricity:
1x10A, 1X4A, 1X6A
While it should be:
1X4A, 1X6A, 1X10A
Does anyone know how to tweak it so it will give it back in the order I want it to be?
you should do this:
to replace letter of the key "name"
replace the comma for dot
convert the number in float
sort the array
Like this:
var PhysicalCapacities = [];
for (var i = 0; i < values.length; i++){
if (values[i].type == type){
PhysicalCapacities.push(values[i]);
}
}
var sortedArray = _(PhysicalCapacities).chain().sortBy(function(PhysicalCapacity) {
return parseFloat(PhysicalCapacity.name.replace(/[^0-9$.,]/g, '').replace(',','.'));
}).value();
Related
I have a necessity to order an array of objects using another list order, but here's the catch the strings on the list only fulfill partially a particular attribute from the object.
So I need to check the object 'name' attribute to verify if it's in the order as shown in the toSort variable.
Basically, I have something like this:
var toSort = ['Engeneering', 'Design', 'Implementation', 'Test', 'Homologation'];
var unsortedList = [
{id: 1, name: 'Rework for Test phase'},
{id: 2, name: 'Rework for Homologation phase'},
{id: 3, name: 'Rework for Design phase'},
{id: 4, name: 'Excluding Alteration on Implementation phase'}]
I need a function to order as shown in the toSort variable
Like this:
var sortedList = [
{id: 3, name: 'Rework for Design phase'},
{id: 4, name: 'Excluding Alteration on Implementation phase'},
{id: 1, name: 'Rework for Test phase'},
{id: 2, name: 'Rework for Homologation phase'}];
And I did it in two ways. This one works on Firefox:
function orderByPhase(unsortedList) {
var sortedlist = [];
for(var i = 0; i <= toSort.lenght; i++) {
sortedList = unsortedList.sort(a , b) {
return a.nome.includes(toSort[i]) && !b.nome.includes(toSort[i]) ? 1 : -1;
}
}
return sortedList;
}
But it doesn't work on Chrome. This one below, Works on Chrome, but it doesn't on Firefox:
function orderByPhase(unsortedList) {
var sortedlist = [];
for(var i = 0; i <= toSort.lenght; i++) {
sortedList = unsortedList.sort(a , b) {
var aFirst = a.nome.includes(this.fases[i]) ? 1 : -1;
var bFirst = 0;
bFirst = aFirst && !b.nome.includes(this.fases[i]) ? 1 : -1;
return bFirst;
}
}
return sortedList;
}
Can someone help me find a middle ground here?
Your code has several problems:
lenght is mispelled in both versions, so the loop will not iterate at all
i should not increase up and equal to length, as that will lead to an undefined this.phases[i] reference
Not sure what unsortedList.sort(a, b) was intended to do: a and b are undefined, and sort takes only one (optional) argument. If there is an argument it should be a function. Maybe you intended to write an arrow function like this: sort((a,b) =>?
A sort callback function should be able to return 0 when there is no reason to enforce a certain order.
Even if this could be made to work, it is not efficient at all, since you call sort in every iteration, which would give this a time complexity of O(mnlogn) where m is the length of toSort (which I assume is the same array as this.phases), and n the size of the array to sort.
I would suggest first to map the input array to enrich it with the index each value belongs to: the index in the toSort array. Only then call sort on that, with a callback that will compare those indexes. Then finally remove those indexes again with a map call.
Here is an implementation:
var toSort = ['Engeneering', 'Design', 'Implementation', 'Test', 'Homologation'];
var unsortedList = [
{id: 1, name: 'Rework for Test phase'},
{id: 2, name: 'Rework for Homologation phase'},
{id: 3, name: 'Rework for Design phase'},
{id: 4, name: 'Excluding Alteration on Implementation phase'}
];
var sorted = unsortedList.map(o => [o, toSort.findIndex(word => o.name.includes(word))])
.sort(([,a], [,b]) => a - b)
.map(([o]) => o);
console.log(sorted);
This has a time complexity of O(nm + nlogn).
I am trying to rebuild an array ,so I need suggestion on doing it using best practices.
I have an array object as follows:
MainObject:
0:"Namebar"
1: Object
Name: "Title1"
Url: "Url1"
2: Object
Name: "Title2"
Url: "Url2"
3: Object
Name: "Title3"
Url: "Url1"
In the above since the "url" is same , I want to group it same object and I am expecting the output in the following format:
0: "Url1"
1: Object
Name : "Title1"
Url: "Namebar"
2: Object
Name : "Title3"
Url: "Namebar"
1: "Url2"
1: Object
Name : "Title2"
Url: "Namebar"
I am trying to have two arrays and loop through the MainObject for swapping the items which I know is not only a teadious process but very much high on time complexity.
For example like :
var extract1 = MainObject[0];
var extract2 = using for loop to extract and swap ......
I am not getting any other way of achieving this. Any approach for this in javascript/jquery?
This should do the job:
var extract1 = MainObject[0];
var newArray = {};
var newArrProp;
var extract1Props = Object.keys(extract1);
for( i = 0; i< extract1Props.length; i++)
{
newArrProp = extract1Props[i];
var nestedObjects = extract1[newArrProp];
for(j = 0; j < nestedObjects.length; j++)
{
if(!newArray[nestedObjects[j].Url])
{
newArray[nestedObjects[j].Url] = [];
}
newArray[nestedObjects[j].Url].push({Name:nestedObjects[j].Name,Url:newArrProp});
}
}
Working fiddle
You could use some loops.
var MainObject = [{ "Namebar": [{ Name: "Title1", Url: "Url1" }, { Name: "Title2", Url: "Url2" }, { Name: "Title3", Url: "Url1" }] }],
object2 = [];
MainObject.forEach(function (a) {
Object.keys(a).forEach(function (k) {
a[k].forEach(function (b) {
var temp = {};
if (!this[b.Url]) {
temp[b.Url] = [];
this[b.Url] = temp[b.Url];
object2.push(temp);
}
this[b.Url].push({ name: b.Name, Url: k });
}, this);
}, this);
}, Object.create(null));
document.write('<pre>object2 ' + JSON.stringify(object2, 0, 4) + '</pre>');
document.write('<pre>MainObject ' + JSON.stringify(MainObject, 0, 4) + '</pre>');
I have two JSON objects columnsData and columns when assigning columnsData value to columns both values are changed.
var columnsData = [
{id: "id"},
{id: "root_task_assignee"},
{id: "root_task_id"},
{id: "root_task_status"},
{id: "root_task_tracker"},
{id: "rt_category"},
{id: "rt_priority"},
{id: "rt_subject"},
]
var columns = [];
using the below function I assigned the columnsData value to columns object, and also added some additional fields
for(i = 0;i < columnsData.length; i++){
columns[i] = columnsData[i];
columns[i]["name"] = columnsData[i]["name"] || columnsData[i]["id"];
columns[i]["type"] = columnsData[i]["id"]["type"] || "string";
}
but after assigning both have the same values. How the old JSON columnsData value was changed? is there any other way to assign values
columns[i] = columnsData[i] does not copy the data, it makes an additional reference to the same data.
For example, say you give Mr. Random Jones a nickname, "Cozy". If you give Cozy an envelope to hold, are you surprised if Mr. Jones is now holding an envelope too?
Same thing here. If you change columns[i], you are also changing columnsData[i], since they are the same object.
You would have to clone it if you wanted to have them be different. In this case, you just have to make a new object with id:
columns[i] = { id: columnsData[i].id };
In general, you would do well to find a nice clone function.
If it is required to keep original array pure (unchanged) we should use map method of array.
var columnsData = [
{id: "id"},
{id: "root_task_assignee"},
{id: "root_task_id"},
{id: "root_task_status"},
{id: "root_task_tracker"},
{id: "rt_category"},
{id: "rt_priority"},
{id: "rt_subject"},
]
var columns = columnsData.map(function(obj){
var rObj = {};
rObj[obj.key] = obj.value;
rObj["name"] = obj.value;
.....
return rObj;
});
Logic can be added in map method to create new array as required. Hope it helps.
columns[i] = columnsData[i] will not copy content from one object to another but it will an reference of the columnsData[i]. As they are refereeing to same object, change in property of one object will affect the primary object which is being refereed.
Try this:
var columnsData = [{
id: "id"
}, {
id: "root_task_assignee"
}, {
id: "root_task_id"
}, {
id: "root_task_status"
}, {
id: "root_task_tracker"
}, {
id: "rt_category"
}, {
id: "rt_priority"
}, {
id: "rt_subject"
}, ]
var columns = [];
for (i = 0; i < columnsData.length; i++) {
var obj = {};
obj["name"] = columnsData[i]["name"] || columnsData[i]["id"];
obj["type"] = columnsData[i]["id"]["type"] || "string";
columns.push(obj)
}
alert(JSON.stringify(columns));
alert(JSON.stringify(columnsData));
I'm looking for the cleanest and coolest way to merge related arrays together in JavaScript.
My example is this:
I get two JSON arrays from my API: Issues and Locations.
Issues have a location_id and as a result I want to give each Issue a location field which has the correct location object depending on the Issue's location_id.
If I had this data:
var issues = [{id: 1, title: 'issue 1', location_id: 1}, {id: 12, title: 'issue 1', location_id: 2}];
var locations = [{id: 1, name: 'location 1'}, {id: 2, name: 'location 2'}];
The ugly solution would be:
for(i = 0; i < issues.length; ++i) {
for(j = 0; j < locations.length; ++j) {
if(issues[i].location_id == locations[j].id) {
issues[i].location = locations[j];
break;
}
}
}
The resulting issues array would be:
[[object Object] {
id: 1,
location: [object Object] {
id: 1,
name: "location 1"
},
location_id: 1,
title: "issue 1"
}, [object Object] {
id: 12,
location: [object Object] {
id: 2,
name: "location 2"
},
location_id: 2,
title: "issue 1"
}]
I was trying (and failing) to come up with a shorter solution or even a one liner using .map().
Any guidance appreciated!! :)
Use map and filter:
issues.map(function (issue) {
issue.location = locations.filter(function(location) {
return issue.location_id === location.id;
})[0];
return issue;
});
Use an object to keep the map, then time complexity will be O(n+m) instead of O(n*m).
var issues = [{id: 1, title: 'issue 1', location_id: 1}, {id: 12, title: 'issue 1', location_id: 2}];
var locations = [{id: 1, name: 'location 1'}, {id: 2, name: 'location 2'}];
var binds = function(locationList, issueList) {
var locMap = {};
// clone. If you want to directly modify the issues, this line is no need.
issueList = JSON.parse(JSON.stringify(issueList));
// construct map from location list.
locationList.forEach(function(location) {
locMap[location.id] = location;
});
// Use the map to bind location and issue.
issueList.forEach(function(issue) {
var loc = locMap[issue.location_id];
if (loc) {
issue.location = loc;
}
});
// If you don't want to clone, this line is no need.
return issueList;
};
var bindResult = binds(locations, issues);
console.log(bindResult);
You can use forEach and filter
var result = issues.forEach(function (issue) {
issue.location = locations.filter(function (location) {
return location.id == issue.location_id;
})[0]
})
which gives you this output when you console.log(result)
[{
"id": 1,
"title": "issue 1",
"location_id": 1,
"location": {
"id": 1,
"name": "location 1"
}
}, {
"id": 12,
"title": "issue 1",
"location_id": 2,
"location": {
"id": 2,
"name": "location 2"
}
}]
1. you can optimize your code to :
var locationObj = {};
for(i = 0; i < location.length; i++) {
locationObj[location[i].id] = location[i];
}
for(i = 0; i < issues.length; i++) {
if(issues[i].location_id){
issues[i].location = locationObj[location_id]
}
}
It will cache all location in one object and will directly use that location detail it as that object's property.It will be faster in execution rather than using filter or map on location array each time.
2. if your location's id and location array's index are in sync then following would be a better and faster solution.
for(i = 0; i < issues.length; i++) {
if(issues[i].location_id){
issues[i].location = locations[location_id-1]
}
}
I have an array of javascript objects like the following:
var food = [
{id: 1, name: 'Apples', owned: true },
{id: 2, name: 'Oranges', owned: false },
{id: 3, name: 'Bananas', owned: true }
];
Then I receive another array with the following data:
var newFood = [
{id: 1, name: 'Peas'},
{id: 2, name: 'Oranges'},
{id: 3, name: 'Bananas'},
{id: 4, name: 'Grapefruits'}
];
How can I update the previous food array with the new information in newFeed, without overwriting the original owned property, while adding an owned: false to any new object?
Keep in mind this is plain javascript, not jQuery.
You'd probably want to index food by id so make food an object instead of an array:
var food = {
1: {name: "Apples", owned: true},
//...
}
then iterate over newFood and update the fields appropriately.
I think you can use underscore.js for fix the problem.
var arrayObj = [
{Name:'John',LastName:'Smith'},
{Name:'Peter',LastName:'Jordan'},
{Name:'Mike',LastName:'Tyson'}
];
var element = _.findWhere(arrayObj, { Name: 'Mike' });
element.Name="SuperMike";
console.log(arrayObj);
This works:
var temp = {};
for (var i = 0, l = food.length; i < l; i += 1) {
temp[food[i].name] = true;
}
for (var i = 0, l = newFood.length; i < l; i += 1) {
if ( !temp[newFood[i].name] ) {
food.push( { id: food.length + 1, name: newFood[i].name, owned: false });
}
}
The first for statement will populate the temp object with the fruit names from the food array, so that we know which fruits exist in it. In this case, temp will be this:
{ "Apples": true, "Oranges": true, "Bananas": true }
Then, the second for statement checks for each fruit in newFood if that fruit exists in temp, and if it doesn't, if pushes a new array item into the food array.
some thing like this? JSFiddle Example
JavaScript
function updateFood( newFood, oldFood ) {
var foodLength = oldFood.length - 1;
for (var i = 0; i < newFood.length; i++) {
if (i > foodLength) { //add more if needed
newFood[i].owned = false;
oldFood.push(newFood[i]);
} else if (!food[i].owned) { //replace if needed
newFood[i].owned = false;
oldFood[i] = newFood[i];
}
}
}