Related
I am trying to use an javascript algorithm to convert the data from products mode to reward mode, please help me :
var products = [{
id: "65864",name_fa:"پک دفتر 40 برگ وزيري شوميز کلاسيک 40 ",
details:[{master: 5,slave: 0,slave2: 0},{master: 11,slave: 0,slave2: 0}]
},{
id: 67532,name_fa: "100-بازی لونا",
details:[{master: 0,slave: 5,slave2: 0}]
}]
TO :
reward: [
{products: [
{
id: "65864",
name_fa:"پک دفتر 40 برگ وزيري شوميز کلاسيک 40" ,
"master": "5",
"slave": "0",
"slave2": "0"
},
{
"id": "67532",
"name_fa":"100-بازی لونا" ,
"master": "0",
"slave": "5",
"slave2": "0"
}
],
},
{"products": [
{
"id": "65864",
"name_fa":"پک دفتر 40 برگ وزيري شوميز کلاسيک 40" ,
"master": "11",
"slave": "0",
"slave2": "0"
},
{
"id": "67532",
"name_fa":"100-بازی لونا" ,
"master": "0",
"slave": "5",
"slave2": "0"
}
],
}
]
example:
[1,2],[3]
to
[1,3],[2,3]
I am trying to use an javascript algorithm to convert the data from products mode to reward mode, please help me
It's called cartesian product. I'm reusing a function and apply it on 2 arrays. The products, and the details. Then I combine those arrays (should be same length) into the required result.
// from: https://stackoverflow.com/a/36234242/3807365
function cartesianProduct(arr) {
return arr.reduce(function(a, b) {
return a.map(function(x) {
return b.map(function(y) {
return x.concat([y]);
})
}).reduce(function(a, b) {
return a.concat(b)
}, [])
}, [
[]
])
}
var products = [{
id: "65864",
name_fa: "پک دفتر 40 برگ وزيري شوميز کلاسيک 40 ",
details: [{
master: 5,
slave: 0,
slave2: 0
}, {
master: 11,
slave: 0,
slave2: 0
}]
}, {
id: 67532,
name_fa: "100-بازی لونا",
details: [{
master: 0,
slave: 5,
slave2: 0
}]
}];
var input = products.reduce(function(agg, item) {
agg.push(item.details);
return agg;
}, []);
var a = cartesianProduct(input);
// same for the id and names
var input2 = products.reduce(function(agg, item) {
var ids = []
item.details.forEach(function(_) {
ids.push({
id: item.id,
name_fa: item.name_fa
})
})
agg.push(ids);
return agg;
}, []);
var b = cartesianProduct(input2);
//console.log(JSON.stringify(a, null, 2));
//console.log(b)
var reward = [];
for (var i = 0; i < a.length; i++) {
var newGroup = {
products: []
}
for (var j = 0; j < a[i].length; j++) {
var newMan = {}
newGroup.products.push({
...b[i][j],
...a[i][j]
})
}
reward.push(newGroup)
}
console.log(reward)
.as-console-wrapper {
max-height: 100% !important
}
I want to compare the dates from 2 arrays and push the name from the matching date inside a new array. And then push '0' for missing dates.
This is what I've tried
var data = [{
name: 'Amy',
date: '2020-01-01'
}, {
name: 'John',
date: '2020-01-02'
}, {
name: 'Sara',
date: '2020-01-04'
}];
var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
var newData = [];
var len = data.length;
for (var i = 0; i < len; i++) {
if (data[i].date == fulldate[i]) {
newData.push(data[i].name);
} else if (data[i].date != fulldate[i]) {
newData.push("0")
}
}
console.log(newData);
The problem is that it stops after encountering the unmatched date:
Amy,John,0
This is what I need
Amy, John, 0, Sara, 0
The best approach is always to use map and filter. Use map function on the fulldate The obj filters out the object (if present) with same date, as of current el value. I have used ternary operator in the return statement which returns name if object is present, and 0 otherwise.
var data = [{
name: 'Amy',
date: '2020-01-01'
}, {
name: 'John',
date: '2020-01-02'
}, {
name: 'Sara',
date: '2020-01-04'
}];
var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
var result = fulldate.map((el) => {
let obj = data.filter(item => (item.date == el))
return (obj[0]) ? obj[0].name : 0;
})
console.log(result);
On your code, you have used for-loop based on data variable length but the result has the same length with fulldate so it will be looped based on fulldate variable length.
Inside loop, you have compared fulldate[i] == data[i].date so compared only same index. Inside the loop, you need to use another loop to find the index of the matched date.
Instead of using for loop, you can simply do it using Array.prototype.map function. (Inside map function, using Array.prototype.findIndex, you can find the matched date index.)
var data = [{
name: 'Amy',
date: '2020-01-01'
}, {
name: 'John',
date: '2020-01-02'
}, {
name: 'Sara',
date: '2020-01-04'
}];
var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
const result = fulldate.map((date) => {
const existed = data.findIndex(item => item.date === date);
return existed >= 0 ? data[existed].name : 0
});
console.log(result);
var data = [{
name: 'Amy',
date: '2020-01-01'
}, {
name: 'John',
date: '2020-01-02'
}, {
name: 'Sara',
date: '2020-01-04'
}];
var fulldate = [
'2020-01-01',
'2020-01-02',
'2020-01-03',
'2020-01-04',
'2020-01-05'
];
var newData = [];
for(var i = 0; i < fulldate.length; i++) {
var found = false;
for(var k in data) {
if(data[k].date == fulldate[i]) {
newData.push(data[k].name);
found = true;
break;
}
}
if(!found)
newData.push("0");
}
console.log(newData);
Suppose the arrays are ordered by date already, use a variable dataIdx to iterate data and Array.map() to simplify the for loop.
var data = [{name:'Amy', date:'2020-01-01'}, {name:'John', date:'2020-01-02'}, {name:'Sara', date:'2020-01-04'}];
var fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
var dataIdx = 0;
var newData = fulldate.map(date => data[dataIdx] && data[dataIdx].date == date ? data[dataIdx++].name : '0');
console.log(newData);
for variable declaration, use 'let' or 'const' instead of var. reason: var vs let vs const
And, the result you are looking for can be done using map & find js func.
const fulldate = ["2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04", "2020-01-05"];
const data = [
{name: "Amy", date: "2020-01-01"},
{name: "John", date: "2020-01-02"},
{name: "Sara", date: "2020-01-04"}
];
const result = fulldate.map(date => {
const matchingDate = data.find(nameDateObj => nameDateObj['date'] === date);
return matchingDate ? matchingDate['name'] : 0;
});
console.log(result)
fyi: this can also be done using findIndex instead of find too.
fulldate.map(date => {
const matchingDateIndex = data.findIndex(nameDateObj => nameDateObj['date'] === date);
return matchingDateIndex > -1 ? data[matchingDateIndex]['name'] : 0;
});
For shortest solution you should combine map and find. Here is a oneliner:
const data = [{
name: 'Amy',
date: '2020-01-01'
}, {
name: 'John',
date: '2020-01-02'
}, {
name: 'Sara',
date: '2020-01-04'
}];
const fulldate = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'];
const result = fulldate.map(x => (data.find(y => y.date === x) || {name: 0}).name)
console.log(result)
I currently have an array that has the following structure:
data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
But I would like to restructure the array to get something like this:
data = [
{
name: "thing1",
info: [{
time: 100,
count: 3
}, {
time: 1000,
count: 7
}, {
}]
},
{
name: "thing2",
info: [{
time: 100,
count: 2
}, {
time: 1000,
count: 0
}, {
}]
}
];
So basically the key would have to be switched from time to name, but the question is how. From other posts I have gathered that using the map function might work, but since other posts had examples to and from different structures I am still not sure how to use this.
There are a number of ways to achieve this however, the key idea will be to perform a nested looping of both data items and their (nested) info items. Doing that allows your algorithm to "visit" and "map" each piece of input data, to a corresponding value in the resulting array.
One way to express that would be to use nested calls to Array#reduce() to first obtaining a mapping of:
name -> {time,count}
That resulting mapping would then be passed to a call to Object.values() to transform the values of that mapping to the required array.
The inner workings of this mapping process are summarized in the documentation below:
const data=[{time:100,info:[{name:"thing1",count:3},{name:"thing2",count:2},{}]},{time:1e3,info:[{name:"thing1",count:7},{name:"thing2",count:0},{}]}];
const result =
/* Obtain array of values from outerMap reduce result */
Object.values(
/* Iterate array of data items by reduce to obtain mapping of
info.name to { time, count} value type */
data.reduce((outerMap, item) =>
/* Iterate inner info array of current item to compound
mapping of info.name to { time, count} value types */
item.info.reduce((innerMap, infoItem) => {
if(!infoItem.name) {
return innerMap
}
/* Fetch or insert new { name, info } value for result
array */
const nameInfo = innerMap[ infoItem.name ] || {
name : infoItem.name, info : []
};
/* Add { time, count } value to info array of current
{ name, info } item */
nameInfo.info.push({ count : infoItem.count, time : item.time })
/* Compound updated nameInfo into outer mapping */
return { ...innerMap, [ infoItem.name] : nameInfo }
}, outerMap),
{})
)
console.log(result)
Hope that helps!
The approach I would take would be to use an intermediate mapping object and then create the new array from that.
const data = [{time: 100, info: [{name: "thing1", count: 3}, {name: "thing2", count: 2}, {}]}, {time: 1e3, info: [{name: "thing1", count: 7}, {name: "thing2", count: 0}, {}]} ];
const infoByName = {};
// first loop through and add entries based on the name
// in the info list of each data entry. If any info entry
// is empty ignore it
data.forEach(entry => {
if (entry.info) {
entry.info.forEach(info => {
if (info.name !== undefined) {
if (!infoByName[info.name]) {
infoByName[info.name] = [];
}
infoByName[info.name].push({
time: entry.time,
count: info.count
});
}
});
}
});
// Now build the resulting list, where name is entry
// identifier
const keys = Object.keys(infoByName);
const newData = keys.map(key => {
return {
name: key,
info: infoByName[key]
};
})
// newData is the resulting list
console.log(newData);
Well, the other guy posted a much more elegant solution, but I ground this one out, so I figured may as well post it. :)
var data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
var newArr = [];
const objInArray = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o)
return true;
}
return false;
}
const getIndex = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o) {
return i;
}
}
return false;
}
const getInfoObj = (t, c) => {
let tmpObj = {};
tmpObj.count = c;
tmpObj.time = t;
return tmpObj;
}
for (var i=0; i < data.length; i += 1) {
let t = data[i].time;
for (var p in data[i].info) {
if ("name" in data[i].info[p]) {
if (objInArray(data[i].info[p].name, newArr)) {
let idx = getIndex(data[i].info[p].name, newArr);
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newArr[idx].info.push(newInfoObj);
} else {
let newObj = {};
newObj.name = data[i].info[p].name;
let newInfo = [];
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newInfo.push(newInfoObj);
newObj.info = newInfo;
newArr.push(newObj);
}}
}
}
console.log(newArr);
try to use Object.keys() to get the key
I am trying to add the unique values for the fiddle below in the output I want
{ category: 'fos', value: 70 },
{ category: 'nyedva', value: 30 }
I am able to get the unique values in the array not sure where to add the values
http://jsfiddle.net/mj3q0sk3/
var catalog={
products : [
{ category: 'fos', value: 10 },
{ category: 'fos', value: 20 },
{ category: 'nyedva', value: 30 },
{ category: 'fos', value: 40 },
]
};
var categories = [];
var sum=[];
$.each(catalog.products, function(index, value) {
if ($.inArray(value.category, categories)==-1) {
categories.push(value.category);
}
else {
console.log("CAt Val:" +value.category);
var total=value.value;
sum.push(total);
}
});
console.log(categories);
console.log(sum);
You can use forEach() loop to return desired result.
var catalog = {"products":[{"category":"fos","value":10},{"category":"fos","value":20},{"category":"nyedva","value":30},{"category":"fos","value":40}]}
var result = [];
catalog.products.forEach(function(e) {
var c = e.category;
!this[c] ? (this[c] = e, result.push(this[c])) : this[c].value += e.value
}, {})
console.log(result)
You can do this without the need for jQuery:
var res = catalog.products.reduce(function(res, product) {
if (!res.hasOwnProperty(product.category)) {
res[product.category] = 0;
}
res[product.category] += product.value;
return res;
}, {});
console.log(res);
This yields:
{ fos: 70, nyedva: 30 }
If you want it as an array of categories:
console.log(Object.keys(res).map(function(key) { return { category: key, value: res[key] }; }));
This will give you:
[ { category: 'fos', value: 70 },
{ category: 'nyedva', value: 30 } ]
I have been trying for hours to do this using json.js but is just too much for something that seems simple. I have this example data:
var hotels = [
{ id: 101, Name: "Hotel 101", WebFacilities: [8, 9, 10] },
{ id: 102, Name: "Hotel 101", WebFacilities: [8] },
{ id: 103, Name: "Hotel 101", WebFacilities: [8, 10] }
];
var facilities = [
{ id: 8, Name: "Facility 8" },
{ id: 9, Name: "Facility 9" },
{ id: 10, Name: "Facility 10" }
];
I want to get this:
var selectedFacilities = [
{ id: 8, Name: "Facility 8", Count: 3 },
{ id: 9, Name: "Facility 9", Count: 1 },
{ id: 10, Name: "Facility 10", Count: 2 }
];
How do I do this?
So it appears you're trying to count how many of each facility there is.
Here's one way to write the query using C#:
var hotelFacilities =
from hotel in hotels
from id in hotel.WebFacilities
group id by id;
var query =
from facility in facilities
join g in hotelFacilities on facility.id equals g.Key
select new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
};
Now if you can picture this using the method syntax, it is almost a 1:1 transformation to the linq.js version.
Note the way the compiler translates the above will usually include the GroupBy() call within the previous SelectMany() call. However written this way will make writing the linq.js equivalent query easier and less awkward.
var hotelFacilities = hotels
.SelectMany(hotel => hotel.WebFacilities)
.GroupBy(id => id);
var query = facilities
.Join(
hotelFacilities,
facility => facility.id,
g => g.Key,
(facility, g) => new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
}
);
And the equivalent linq.js query.
var hotelFacilities = Enumerable.From(hotels)
.SelectMany("hotel => hotel.WebFacilities")
.GroupBy("id => id")
.ToArray();
var query = Enumerable.From(facilities)
.Join(
hotelFacilities,
"facility => facility.id",
"g => g.Key()",
"(facility, g) => { id: facility.id, Name: facility.Name, Count: g.Count() }"
).ToArray();
Use this:
var selectedFacilities = facilities;
for(var i = 0; i < facilities.length; i++) {
for(var j = 0; j < hotels.length; j++) {
if(hotels[j]["id"] == facilities[i]["id"]) {
// Add data
selectedFacilities[i]["Count"] = hotels[i]["WebFacilities"].length;
} else {
selectedFacilities[i]["Count"] = 0;
}
}
}