I have an array data format coming from back-end which looks like:
Array
[{"ckey::"C1","date":"0506","rows":17},
{"ckey::"C1","date":"0706","rows":7},
{"ckey::"C2","date":"0706","rows":13},
{"ckey::"C2","date":"0806","rows":11}]
So for few days C1 data is there and few days C2 data.
Only one day has C1 and C2 data both.
I want to build an array like for C1 and C2
[[17,7,0],[0,13,11]]
First nested array for C1 where third value is 0 because for 0806 date the value was not present.
Second nested array for C2 where first value is 0 because for 0506 date the value was not present.
Please help. I cannot form the array effectively.
I think it would be O(n^3) solution. But please help with the same.
UPDATE
Here was my approach, I could not post the code here but it looks something like this.
I was getting date values in separate array like and I filter for unique days.
angular.forEach(data, function(obj){
if(timeData.indexOf(obj.date) === -1)
timeData.push(obj.date);
});
Then
ckey array _distinctckeyArray also were there containing values ["C1","C2"].
angular.forEach(_distinctckeyArray,function(_ckey){
var _formattedDataArrItem = [];
angular.forEach(timeData,function(_dateTimeString) {
var _tempDataVolume = [];
angular.forEach(_data,function(_dataObj) {
if(_dataObj.date === _dateTimeString) {
if(_dataObj.ckey === _ckey) {
_tempDataVolume.push(_dataObj.rows);
}else {
_tempDataVolume.push(0);
}
}
});
});
You can make an object dates that will have date properties. Initialize the values to 0
You reduce to group the array. Use Object.values to convert the object into an array.
let arr = [{ckey:"C1","date":"0506","rows":17},{ckey:"C1","date":"0706","rows":7},{ckey:"C2","date":"0706","rows":13},{ckey:"C2","date":"0806","rows":11}];
//Make an object with property dates. assign all property to 0 as initial value.
//Expected output:
//{"0506":0,"0706":0,"0806":0}
let dates = arr.reduce((c, v) => Object.assign(c, {[v.date]: 0}), {});
//Loop thru the array using `reduce`.
//This is to group the array to object using the ckey as the key
//After grouping, use `Object.values` to convert the object into array
let result = Object.values(arr.reduce((c, {ckey,date,rows}) => {
c[ckey] = c[ckey] || { ...dates }; //Check if c[ckey] exist. If it does not, "clone" the dates object.
c[ckey][date] = rows; //Overide the initial value 0 to the rows value
return c;
}, {})).map(o => Object.values(o));
console.log(result);
I think this is what you are looking for. Let me know.
let data = [{
'ckey': 'C1',
'date': '0506',
'rows': 17
}, {
'ckey': 'C1',
'date': '0706',
'rows': 7
}, {
'ckey': 'C2',
'date': '0706',
'rows': 13
}, {
'ckey': 'C2',
'date': '0806',
'rows': 11
}]
function nested_arrays(array) {
const result = []
const obj = {
c1: [],
c2: []
}
for (let i = 0; i < array.length; i++) {
if (array[i].ckey === 'C1') {
obj.c1.push(array[i].rows)
}
if (array[i].ckey === 'C2') {
obj.c2.push(array[i].rows)
}
}
obj.c1.push(0) // set last value to 0
obj.c2.unshift(0) // set first value to 0
result.push(obj.c1, obj.c2)
return result
}
let _tempDataVolume = nested_arrays(data)
console.log(_tempDataVolume) //=> [ [ 17, 7, 0 ], [ 0, 13, 11 ] ]
let arr = [{"ckey::"C1","date":"0506","rows":17},
{"ckey::"C1","date":"0706","rows":7},
{"ckey::"C2","date":"0706","rows":13},
{"ckey::"C2","date":"0806","rows":11}]
arr.map(res =>{
let c1arr = [],
let c2arr = [],
if(res.ckey== 'C1'){
c1arr.push(res.rows)
}else{ c2arr.push(res.rows) }
})
let newArrr = []
newArr.push(c1arr);
newArr.push(c2arr);
console.log('arr is',newArr)
Related
I have the following JSON:
{
"hominis": [20000, "asd"],
"omint": [30000, "asd"]
}
and I would like to make a function that returns all array names (hominis, omint) whose arr[0] value is under my input value
e.g:
if (myInput <= arr[0]) {
return arrName
}
I would like to go through my arrays (hominis, omint) and return their names if the condition is matched. I believe it has something to do with for loops, but I couldn't do it.
I've started JS two weeks ago so I'm a newbie.
Thank you
You can iterate over the keys of an object like following snippet,
var a = {
"hominis": [20000, "asd"],
"omint": [30000, "asd"]
};
var minValue = 25000;
var keys = Object.keys(a); // Returns all keys in the object
for (let key of keys) { // Loop over all the keys
if (a[key][0] > minValue) { // Check if value at key matches your condition
console.log(key); // return/add to your new array/ or whatever to the matching key
}
}
You did not say how to show your output. I am assuming it will be array of names.
let data = {
hominis: [20000, "asd"],
omint: [30000, "asd"],
};
myInput = 20001;
let x = Object.entries(data).reduce((p, [x, y]) => {
if (myInput <= y[0]) p.push(x);
return p;
}, []);
console.log(x);
You can use "for in obj".
var obj1 = {
"hominis": [20000, "asd"],
"omint": [30000, "asd"]
}
function findMinorThan(obj, limit) {
let res = []
for (const k in obj) {
if (obj[k][0] < limit) {
res.push(k)
}
}
return res
}
console.log(findMinorThan(obj1, 25000));
I need to have a method which needs to check in the valid range between -064.000000 to -180.000000 and 142.000000 to 180.000000. The ranges object that I have looks like the following:
"ranges": {
"range1": {
"min": -180,
"max": -64
},
"range2": {
"min": 142,
"max": 180
}
}
So far, this is what I was able to complete but it doesn't seem to work right:
const mustBeInRangeInclusive = ({ userInput, ranges }) => {
let data_num = _.toNumber(userInput);
for (let i = 0; i < ranges.length; i++) {
return result = data_num >= ranges[i][0] && data_num <= ranges[i][1];
}
};
Can someone please help me complete this method to figure out what am I doing wrong?
Expected output:
-63 -> invalid
-64: valid
181 -> invalid
180: valid
141 -> invalid
142: valid
Few edits, as the question code keeps changing a bit.
First problem - accessing objects properties
If you have an array, you access its values by indeces.
let array = [1, 2, 3];
let firstItem = array[0];
let secondItem = array[1];
If you have object, you access its propeties by their names.
let someObject = { 'name': 'John', 'age': 21 };
let name = someObject.name;
name = someObject['name'];
If you have array of objects, you combine both methods.
let arrayOfObjects = [
{ 'name': 'John', 'age': 21 },
{ 'name': 'Sam', 'age': 23 }
]
let firstObjectsName = arrayOfObjects[0].name;
Second problem - exiting the loop on the first iteration
You call return statement as soon as you enter the loop making it impossible to enter the second iteration. You could store result of each iteration in the array and return it in the end.
const mustBeInRangeInclusive = ({ userInput, ranges }) => {
let results = [];
let data_num = _.toNumber(userInput);
for (let i = 0; i < ranges.length; i++) {
results.push(data_num >= ranges[i].min && data_num <= ranges[i].max);
}
return results;
};
This answer based upon the comment request of OP, and does not solve the issue if filters would be an object.
Assuming you can change the definition, using an array of filters would be a lot easier to work with than an object with filters. You can use the array every method to check if every elements matches a criteria. Use some to check if some (one or more) elements matches a criteria.
const userInput = document.getElementById("user-input");
const ranges = [ // <- changed definition to an array
{ "min": 0, "max": 100 },
{ "min": 50, "max": 150 },
];
userInput.addEventListener("change", () => {
const nr = parseInt(userInput.value, 10);
const coversNr = ({min, max}) => min <= nr && nr <= max;
const withinEveryRange = ranges.every(coversNr);
const withinSomeRange = ranges.some(coversNr);
console.log("withinEveryRange //=>", withinEveryRange);
console.log("withinSomeRange //=>", withinSomeRange );
});
<input id="user-input" type="number" />
const arr = [
{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}
];
I have an array as you can see in the snippet. My issue is I need to check something per day:
For each day when A value > 60 or when B value > 6 then do something.
Else when A value <= 60 and when B value <= 6 then do something else.
And I don't know how to do this check with the current array structure as each step in the loop is a different day. I want to compare all values for one day at the same time.
Is it possible to transform the array to look like this? Then I will be able to compare day per day...
const arr = [
{"datetime":"2018/8/5","valueA":85,"valueB":undefined},
{"datetime":"2018/8/10","valueB":7,"valueA":73}
];
Thank you!
You can make a the date groups by reducing into an object. Then just set the appropriate value in that object. In the end your array will be in the Object.keys() of the grouped object.
[As you might surmise from the comments, the order of the final array is not guaranteed because object keys and values are not guaranteed. If your original data is ordered by date, you should say so in the question because there will be more efficient ways to do this if the order is guaranteed].
const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},{"datetime":"2018/8/10","value":7,"type":"B"},{"datetime":"2018/8/10","value":73,"type":"A"}];
let groups = arr.reduce((obj, {datetime, value, type}) => {
if (!obj[datetime]) obj[datetime] = {datetime, valueA:undefined, valueB:undefined}
let currentKey = type == 'A' ? "valueA" : "valueB"
obj[datetime][currentKey] = value
return obj
},{})
let newArr = Object.values(groups)
console.log(newArr)
This will transform the array as OP asked for, and will respect the order.
const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}];
var daysArr = []
arr.map(function(day){
var keyName = 'value'+day.type
var found = false
var dayObj = {}
for (var i=0; i < daysArr.length; i++) {
if (daysArr[i].datetime === day.datetime) {
daysArr[i][keyName] = day.value;
found = true
break
}
}
if (!found) {
dayObj = {"datetime":day.datetime,valueA:undefined,valueB:undefined}
dayObj[keyName] = day.value
daysArr.push(dayObj)
}
})
console.log(daysArr);
One solution could be using reduce(). Note that if a key is not defined will return undefined (this is exemplified on the second log to the console), so I consider redundant to define, for example "value-B": undefined, unless you want to assign to it another default value.
Warning: As discussed on the comments, you should note that the order of the final result, may not be preserved.
const arr = [
{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}
];
let res = arr.reduce((acc, {datetime, value, type: type}) =>
{
acc[datetime] = acc[datetime] || {};
Object.assign(acc[datetime], {datetime, [`value-${type}`]: value});
return acc;
}, {});
console.log(Object.values(res));
console.log(Object.values(res)[0]["value-B"]);
You could do this:
<html>
<head>
<meta charset="UTF-8"></meta>
<script type="text/javascript">
const arr = [{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}];
var new_arr = group_items(arr)
console.log(new_arr)
function group_items(arr)
{
var ret_arr = []
for(var x=0;x<arr.length;x++)
{
var cur_date = arr[x].datetime
var pos = lookup_date(cur_date, ret_arr)
var obj = {}
obj.datetime = cur_date
if(pos != false)
{
//add to existing item
if(arr[x].type == 'A')
{
ret_arr[pos].valueA = arr[x].value
}
else if(arr[x].type == 'B')
{
ret_arr[pos].valueB = arr[x].value
}
}
else{
if(arr[x].type == 'A')
{
obj.valueA = arr[x].value
}
else if(arr[x].type == 'B')
{
obj.valueB = arr[x].value
}
ret_arr.push(obj)
}
}
return ret_arr
}
function lookup_date(date, arr)
{
/*
returns the position in arr of date
*/
var retval = false
for(var x=0;x<arr.length;x++)
{
if(arr[x].datetime == date)
{
retval = x
break
}
}
return retval
}
</script>
</head>
<body>
</body>
If you don't need the final array to include the datetimes in the same order as the original, then you can just make an object that maps datetimes to the corresponding values and then use Object.values to get the final array. This approach does not guarantee order, since objects are unordered data structures:
const arr = [
{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}
];
const values_by_date = { };
arr.forEach( ({ datetime, type, value }) =>
values_by_date[ datetime ] = {
datetime/*, valueA: undefined, valueB: undefined*/,
...values_by_date[ datetime ], [`value${type}`]: value
}
);
const result = Object.values( values_by_date );
console.log( result );
If you need the final array to include the datetimes in the same order as the original array and the original array is already sorted by datetime, you can do it in a single pass like this:
const arr = [
{"datetime":"2018/8/5","value":85,"type":"A"},
{"datetime":"2018/8/10","value":7,"type":"B"},
{"datetime":"2018/8/10","value":73,"type":"A"}
];
const result = arr.reduce( ({ result, datetime: prev }, { datetime, type, value }) => {
if ( datetime !== prev )
result.push( { datetime/*, valueA: undefined, valueB: undefined*/ } );
Object.assign( result[ result.length - 1 ], { [`value${type}`]: value } );
return { result, datetime };
}, { result: [] } ).result;
console.log( result );
Note: In either snippet you can uncomment /*, valueA: undefined, valueB: undefined*/ if you want the resulting objects to include properties for the missing values.
I have a loop that goes over an array of data plotData. Out of plotData I build another array called visiblePoints. Then I loop over visiblePoints to build an object thisRow, then I add thisRow to an array outside of the loop, called dataArray:
var dataArray = []
for (i = 0; i < plotData.length; i++) {
// This filters datapoints array into another array
var visiblePoints = filterPoints(plotData[i].datapoints)
// Get the string for the thisRow object key name
var selectedParameter = plotData[i].label
for (k = 0; k < visiblePoints.length; k++) {
// Convert visiblePoint first value from ms to date
var timestamp = new Date(visiblePoints[k][0])
// Form the thisRow object that will go into dataArray
// for each loop of visiblePoints
var thisRow = {}
thisRow["Time"] = msToTime(timestamp)
thisRow[selectedParameter] = visiblePoints[k][1]
dataArray.push(thisRow)
}
}
Let's simplify and say I only have 2 element in sub array visisblePoints for each plotData array, like so (each plotData array can have many visiblePoints but I'm simplifying to just 2 for each):
plotData[0].visiblePoints = [[00:00:01, 1], [00:00:02, 4] ...]
plotData[1].visiblePoints = [[00:00:01, 27], [00:00:02, 31] ...]
plotData looks like this on the console:
The visiblePoints array for the k loop is derived off of plotData.datapoints and looks like:
Where visiblePoints[n][0] is a value in ms (that I convert into seconds) and visiblePoints[n][1] is just a float value.
visiblePoints =
[0, 0.0500466109191]
[100, 0.0548114598135]
[200, 0.0550143573252]
[300, 0.0549408536766]
[400, 0.0546117305419]
[... repeat 300+ times...]
After looping over plotData[i] and visiblePoints[k] I end up with:
dataArray = [
{
"Time": 00:00:01,
"foo": 1
},
{
"Time": 00:00:01,
"bar": 27
},
{
"Time": 00:00:02,
"foo": 4
},
{
"Time": 00:00:02,
"bar": 31
},
]
When I had meant to end up with:
dataArray = [
{
"Time": 00:00:01,
"foo": 1,
"bar": 27
},
{
"Time": 00:00:02,
"foo": 4,
"bar": 31
}
]
I think in loop k I need to go over dataArray, check all objects there to see if there is a Time key that matches thisRow["Time"] = msToTime(timestamp), and if so, add thisRow[selectedParameter] = visiblePoints[k][1] to that, if not, create a new object.
Problems:
I'm not sure how to check for this in JS (I'm more experience at Python, and not that much at that
It seems like I'm doing a heck of a lot of loops. I'm not sure adding yet another one to go over the entire dataArray and check all objects to see if a key exists in one of them is best solution here. A plotData.visiblePoints array can be 500+ long.
[EDIT] Simplified the question. Added picture examples. Added text examples of the k array.
You can build an object keyed to the grouping — in this case the timestamp. This will let you randomly access the item you want without searching the array. When you'r done the Object.values of the object will be an array of your grouped objects:
let plotData = [
{
label: 'foo',
visiblePoints: [[`00:00:01`, 1], [`00:00:02`, 4]]
},
{
label: 'bar',
visiblePoints: [[`00:00:01`, 27], [`00:00:02`, 31]]
}
]
let groups = plotData.reduce((obj, {label, visiblePoints}) => {
visiblePoints.forEach(([time, val]) => {
if(!obj[time]) obj[time] = {Time: time} // if we haven't seen this time make a new object at that key
obj[time][label] = val
})
return obj
}, {})
console.log(Object.values(groups))
You could take a Map or a hash table which keeps the reference to the object with the same time.
var map = new Map,
timestamp,
row;
// later in loop
timestamp = msToTime(new Date(visiblePoints[k][0]));
row = map.get(timestamp);
if (!row) {
map.set(timestamp, row = { Time: timestamp });
}
row[selectedParameter] = visiblePoints[k][1];
// at the end assign the array
dataArray = Array.from(map.values())
You could find if an Object has a specific key by calling hasOwnProperty method.
const obj = {
"bar": [1,2,3],
"foo": "im foo"
};
console.log(obj.hasOwnProperty("bar"))
console.log(obj.hasOwnProperty("bar2"))
And you need to follow this pattern.
var dataArray = []
for (i = 0; i < 1; i++) {
for (k = 0; k < 2; k++) {
thisRow = {};
thisRow["Time"] = k+1 * i+1
thisRow["foo"] = i+1
thisRow["var"] = k+1
dataArray.push(thisRow)
}
}
console.log(dataArray)
[NOTE: though similar to this stack question, my question differers significantly (IMO) due to the different structures of the initial variables. Mine is an array, the other questioner's is an object. My array contains nested objects/arrays, the latter of which contain name-value pairs whose values are, unlike the pairs in the other questioner's, not semantically identified.]
I have one big array (arr1) containing 24 objects. Each of the 24 objects contains one object, and one array of six further objects, like so:
var arr1 =
[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]},
...etc, up to hour 24
];
As you can see, each of the 24 objects represents one hour's worth of data on car models and mileage. (What is NOT obvious is that the numeric value in each of the six objects represents miles.)
Now, I want to convert each object in arr1 into one array containing six objects, like below. So Hour 1's data in arr1 would convert to:
var arr2 = [{"car":"audi","miles":1377},{"car":"bmw","miles":716},{"car":"ford","miles":3819},{"car":"mazda","miles":67},{"car":"toyota","miles":11580},{"car":"tesla","miles":0}];
How can I do this? I have tried the following:
var hourx = 1;
var hour = arr1[hourx-1];
var car=hour.car;
for(var hourx1=0;hourx1<car.length;hourx1++){
var xx = car[hourx1];
var newobj = [];
for (var value in xx) {
var chartvar = newobj.push({car:value,miles:xx[value]});
var arr2 = newobj;
}
}
... but if I console.log(arr2); it only gives one array of one object.
I'm stumped. Anybody have an idea how I could accomplish this?
So you want to have an array of arrays as a final result?
var arr1 = [
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]}
];
var arr2 = arr1.map(function(hour){
return hour.car.map(function(car){
var carName = Object.keys(car)[0];
return {
"car": carName,
"miles": car[carName]
}
})
})
https://jsfiddle.net/1jjzeeyz/
Try using .map() , Object.keys()
var arr1 = [{
'hour': 1,
'car': [{
'audi': 1377
}, {
'bmw': 716
}, {
'ford': 3819
}, {
'mazda': 67
}, {
'toyota': 11580
}, {
'tesla': 0
}]
}, {
'hour': 2,
'car': [{
'audi': 1340
}, {
'bmw': 709
}, {
'ford': 3420
}, {
'mazda': 28
}, {
'toyota': 11583
}, {
'tesla': 0
}]
}];
var hours = arr1.map(function(cars, index) {
var carNames = Object.keys(cars.car);
var names = carNames.map(function(c) {
var name = Object.keys(cars.car[c])[0];
var res = {};
res["car"] = name;
res["miles"] = cars.car[c][name];
return res
})
return names
})
console.log(hours)
You would have to iterate over the array. Get the first property (let's hope it stays this way). Then get it value. Then create an object and add it to the array. See fiddle here
var arr1 =
[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]},
];
var arr = [];
for (var i = 0; i< arr1[0].car.length; i++){
var car = arr1[0].car[i];
var key = Object.keys(car)[0];
arr.push({
car: key,
miles: car[key]
});
}
a combination of reduce and map will help. /example:
var
arr1 =[
{'hour':1,'car':[{'audi':1377},{'bmw':716},{'ford':3819},{'mazda':67},{'toyota':11580},{'tesla':0}]},
{'hour':2,'car':[{'audi':1340},{'bmw':709},{'ford':3420},{'mazda':28},{'toyota':11583},{'tesla':0}]}
],
arr2 = arr1.reduce(function (collector, item) {
collector.push(item.car.map(function (car/*, idx, list*/) {
var
make = Object.keys(car)[0]
;
return {
"car" : make,
"miles" : car[make]
}
}));
return collector;
}, [])
;
console.log("arr2 : ", arr2);