I'm trying to get some array data into a particular format so I can use google linechart. But I can't quite get it right.
Right now I have the format
//format [date, id, count
var data = [
["2014-04-01", "1", "100"],
["2014-04-02", "1", "200"],
["2014-04-03", "1", "150"],
["2014-04-04", "1", "5"],
["2014-04-01", "2", "200"],
["2014-04-02", "2", "600"],
["2014-04-03", "2", "15"],
["2014-04-04", "2", "25"],
["2014-04-01", "3", "99"],
["2014-04-02", "3", "85"],
["2014-04-03", "3", "555"],
["2014-04-04", "3", "0"]
];
I need to get it into the format:
var reformatted = [
['Date', '1', '2', '3'],
['2014-04-01', 100, 200, 99],
['2014-04-02', 200, 600, 85],
['2014-04-03', 150, 15, 555],
['2014-04-04', 5, 25, 0]
]);
var graph = [["date"]];
//first element of array to be populated with array of ID's
//always second element of inner arrays
//these will be the lines of the graph
for (var i = 0; i < data.length; i++){
if (graph[0].indexOf(data[i][1]) < 0){
graph[0].push(data[i][1]);
}
}
This puts me in a pretty good place. I get:
Array[1]]
0: Array[4]
0: "date"
1: "1"
2: "2"
3: "3"
But I'm stumped on how to get the rest of the data in the appropriate format. Any ideas?
Tried this. No good result.
for (i = 0; i < data.length; i++){
graph[i + 1] = graph[i + 1] || [];
graph[i + 1].push(data[i][2]);
}
Logic:
First generate this by iterating through the initial array finding unique dates.
[
['Date'],
['2014-04-01'],
['2014-04-02'],
['2014-04-03'],
['2014-04-04']
]
Then convert the generated array as follows again iterating through the initial array finding unique numbers. Also generate list of unique numbers.
[
['Date','1','2','3'],
['2014-04-01'],
['2014-04-02'],
['2014-04-03'],
['2014-04-04']
]
Now iterate through above array, and for each item iterate through the number list and find matches from the initial array where date and number matches. place the matches in the above array. Place a null if not found. You should get the following. I have done this in php but not in javascript.
[
['Date','1','2','3'],
['2014-04-01', null, 100, 200],
['2014-04-02', 100, 400, 500],
['2014-04-03', 200, null, 100],
['2014-04-04', 100, 300, 100]
]
Good Luck!
addition
In php:
$originalData = array(
array("2014-04-01", '1', '200'),
array("2014-04-02", '1', '300'),
array("2014-04-03", '1', '400'),
array("2014-04-04", '1', '200'),
array("2014-04-01", '2', '400'),
array("2014-04-02", '2', '100'),
array("2014-04-03", '2', '200'),
array("2014-04-04", '2', '100'),
array("2014-04-01", '3', '200'),
array("2014-04-02", '3', '600'),
array("2014-04-03", '3', '300'),
array("2014-04-04", '3', '900'),
);
result from second step would be:
$graphData = array(
array('Date','1','2','3'),
array('2014-04-01'),
array('2014-04-02'),
array('2014-04-03'),
array('2014-04-04'),
);
list of numbers would be:
$numbers = array('1','2','3');
I would then do the third step as follows:
$i = 0;
foreach($graphData as $graphDataItem) {
if ($graphDataItem[0]!='Date') { // ignore the first index
$j = 1; // 0 is date column
foreach($numbers as $number) {
foreach($originalData as $originalDataItem) {
// set the value to null until found
if (!isset($graphData[$i][$j]))
$graphData[$i][$j] = null;
if ($originalDataItem[0] == $graphDataItem[0] && // check date match
$originalDataItem[1] == $number) { // check number match
$graphData[$i][$j] = $originalDataItem[2];
break;
}
}
$j++;
}
}
$i++;
}
The resulting $graphData would be:
array
(
0 => array
(
0 => 'Date'
1 => '1'
2 => '2'
3 => '3'
)
1 => array
(
0 => '2014-04-01'
1 => '200'
2 => '400'
3 => '200'
)
2 => array
(
0 => '2014-04-02'
1 => '300'
2 => '100'
3 => '600'
)
3 => array
(
0 => '2014-04-03'
1 => '400'
2 => '200'
3 => '300'
)
4 => array
(
0 => '2014-04-04'
1 => '200'
2 => '100'
3 => '900'
)
)
The above would get you the results in $graphData. However, this would be heavy on processor for larger sets.
Here's an option:
First group all the data by dates, then convert it back into the representation you need.
If you want to automate it a bit more, you could also keep track of the IDs and add the list for the legend automatically.
var data = [
["2014-04-01", "1", "100"],
["2014-04-02", "1", "200"],
["2014-04-03", "1", "150"],
["2014-04-04", "1", "5"],
["2014-04-01", "2", "200"],
["2014-04-02", "2", "600"],
["2014-04-03", "2", "15"],
["2014-04-04", "2", "25"],
["2014-04-01", "3", "99"],
["2014-04-02", "3", "85"],
["2014-04-03", "3", "555"],
["2014-04-04", "3", "0"]
];
var groupByDate = function (data) {
var dataByDate = {};
data.forEach(function (entry) {
var date = entry[0];
var count = entry[2];
if (!(date in dataByDate)) {
dataByDate[date] = [];
}
dataByDate[date].push(count);
});
return dataByDate;
}
var toChartData = function (dataByDate) {
var chartData = [];
for (var date in dataByDate) {
chartData.push([date].concat(dataByDate[date]));
};
return chartData;
};
var byDate = groupByDate(data);
var chartData = toChartData(byDate);
chartData.unshift(['Date', 1, 2, 3]);
console.log(chartData);
Arrays can be rough for things like this, to make it easier it can be best to first convert it to an object to make it easier to work with.
var obj = {};
for(var i=0;i<data.length;i++){
if(!obj[data[i][0]]){ //check if index already exists
obj[data[i][0]] = {}; //create sub object from the index
}
for(var ii=0;ii<data[i].length;ii++){
if(ii!=0){ //since the 0 index is the parent here, ignore it
obj[data[i][0]][ii] = data[i][ii];
}
}
}
This should translate to an object like so:
var data = {
'2014-04-01':{
1:100,
2:200,
3:99
} //continue for the rest
}
So like that you can probably see that converting it into pretty much any other structure will be far easier.
var graph = [['date','1','2','3']];
for(var index in data){
if(data.hasOwnProperty(index)){
var arr = [index];
for(var index2 in data[index]){
if(data[index].hasOwnProperty(index2)){
arr.push(data[index][index2]);
}
}
graph.push(arr);
}
}
Untested and written on the spot, but the concept is there.
Related
I have been looking a simple way to copy/insert/move properties in an object within an array to another object. I came up with a basic logic which does the job perfectly but am not satisfied with this. There has to be a better way, any help here?
var first = [
{
"AGREE_EFF_DATE__0": "02-Aug-2018",
"AGREE_TERM_DATE__0": "30-Apr-2021",
"AGREE_IND__0": "P1",
"P_DBAR_IND__0": "N",
"AGREE_EFF_DATE__1": "01-May-2021",
"AGREE_TERM_DATE__1": null,
"AGREE_IND__1": "NP",
"P_DBAR_IND__1": "N",
"PROVIDER_SPECIALITY__0": "PSYCHOLOGY, CLINICAL",
"PROVIDER_SPECIALITY_CODE__0": "CK"
}
];
var second = [
{
"STATUS": "ACTIVE",
"MEDICARE_NUMBER" : 12345
}
];
for(let i = 0; i < second.length; i++) {
var first_keys = Object.keys(first[i]);
var first_values = Object.values(first[i]);
for(let j = 0; j < first_keys.length; j++) {
second[i][first_keys[j]] = first_values[j];
}
}
console.log(second);
//Output-
[
{
STATUS: 'ACTIVE',
MEDICARE_NUMBER: 12345,
AGREE_EFF_DATE__0: '02-Aug-2018',
AGREE_TERM_DATE__0: '30-Apr-2021',
AGREE_IND__0: 'P1',
P_DBAR_IND__0: 'N',
AGREE_EFF_DATE__1: '01-May-2021',
AGREE_TERM_DATE__1: null,
AGREE_IND__1: 'NP',
P_DBAR_IND__1: 'N',
PROVIDER_SPECIALITY__0: 'PSYCHOLOGY, CLINICAL',
PROVIDER_SPECIALITY_CODE__0: 'CK'
}
]
When possible, you should prefer iteration to manually indexed loops. This means arr.map() or arr.forEach() or arr.reduce(), to name a few.
Also, You can use an object spread to easily merge objects together.
Putting those together, you can reduce this logic to:
const result = first.map((firstObj, i) => ({ ...firstObj, ...second[i] }))
Here we map() over all members of first, which returns a new array where each member is the result of the function. This function takes the array member as the first argument, and the index of that member as the second argument. Then we can use that index to find the corresponding item in the second array.
Then you just spread both objects into a new object to assemble the final result.
var first = [
{ a: 1, b: 2 },
{ a: 4, b: 5 },
];
var second = [
{ c: 3 },
{ c: 6 },
];
const result = first.map((firstObj, i) => ({ ...firstObj, ...second[i] }))
console.log(result)
Which is all perfectly valid typescript as well.
NOTE: there is one difference between my code any yours. Your code modifies the objects in second. My code returns new objects and does not change the contents of second at all.
This is usually the better choice, but it depends on how you use this value and how data is expected to flow around your program.
You need to be careful with iterating, because you can have different count of elements in first and second arrays. So the possible solution will be like this:
const first = [
{
"AGREE_EFF_DATE__0": "02-Aug-2018",
"AGREE_TERM_DATE__0": "30-Apr-2021",
"AGREE_IND__0": "P1",
"P_DBAR_IND__0": "N",
"AGREE_EFF_DATE__1": "01-May-2021",
"AGREE_TERM_DATE__1": null,
"AGREE_IND__1": "NP",
"P_DBAR_IND__1": "N",
"PROVIDER_SPECIALITY__0": "PSYCHOLOGY, CLINICAL",
"PROVIDER_SPECIALITY_CODE__0": "CK"
}
];
const second = [
{
"STATUS": "ACTIVE",
"MEDICARE_NUMBER": 12345
}
];
console.log(mergeAll(first, second));
function mergeAll(firstArray, secondArray) {
const result = [];
const minLength = firstArray.length < secondArray.length ? firstArray.length : secondArray.length;
for (let i = 0; i < minLength; i++) {
result.push({...firstArray[i], ...secondArray[i]});
}
return result;
}
I get problem to call javascript variable from php json_encode().
At javascript, i can't get array.length because there are labels 1:.
I want [res_tmp] array get format like [sample] array (no label number array, example: 1:, 2:).
Thanks for your help.
Echo(false):
res_tmp: {
0: null,
1: {
name: "AAA",
sort: 1
},
2: {
name: "DDD",
sort: 2
},
...
Echo(i wish):
res_tmp: {
null,
{
name: "AAA",
sort: 1
},
{
name: "DDD",
sort: 2
},
...
this is my code:
$tmp = [
[
"name" => "1.AAA",
"sort" => 1,
],[
"name" => "10.CCC",
"sort" => 10,
],[
"name" => "11.BBB",
"sort" => 11,
],[
"name" => "2.DDD",
"sort" => 2,
],[
"name" => "3.EEE",
"sort" => 3,
],
];
for ($i=0; $i < count($tmp); $i++) {
$res_tmp[ $tmp[$i]['sort'] ] = $tmp[$i];
}
$nul = [0,4,5,6,7,8,9,12];
for ($j=0; $j < count($nul); $j++) {
$res_tmp[ $nul[$j] ] = null;
}
$val = [
"sample" => $tmp,
"res_tmp" => $res_tmp,
];
echo json_encode($val);
// echo "<pre>",print_r($val),"</pre>";
welcome to SO. Here is a javascript approach.
What you have here is not an array but a JSON dict, which is an object. You can get the length of it in JavaScript using Object.keys:
let keys = Object.keys(res_tmp);
This will get you the array of keys. You can iterate that and access the values. Like so:
let res_tmp = {
0: null,
1: {
name: "AAA",
sort: 1
},
2: {
name: "DDD",
sort: 2
}
}
let keys = Object.keys(res_tmp);
let arr = [];
for (let j=0;j<keys.length;++j)
{
let item = res_tmp[keys[j]];
arr.push(item);
}
Now arr holds the echo you wish.
I have as a result from an input form a couple of strings and I want them to convert them, so they fit as data for my ajax-request. I am looking for an easy way, but I can't get it right. Basically I want to convert/map this array:
[
{ name: "[1][apples]", value: "2" }
{ name: "[1][melons]", value: "1" }
{ name: "[2][apples]", value: "2" }
{ name: "[2][melons]", value: "4" }
{ name: "[3][apples]", value: "3" }
{ name: "[3][melons]", value: "2" }
]
into
[{"id": 1, "apples": 2, "melons": 1}, {"id": 2, "apples": 2, "melons": 4}, {...}]
Any idea? I would appreciate some hint? I could't not find an easy solution via html though.
Thanks
you can use a for loop to access each element and display them.
Refer to this link. For loop in multidimensional javascript array
Firstly, I have replaced the square brackets using a regular expression and formed a new array. After that, I have merged object having same ID using spread operator.
You can refer to the code below which solves this problem.
let array = [
{ name: "[1][apples]", value: "2" },
{ name: "[1][melons]", value: "1" },
{ name: "[2][apples]", value: "2" },
{ name: "[2][melons]", value: "4" },
{ name: "[3][apples]", value: "3" },
{ name: "[3][melons]", value: "2" }];
let newArray = [];
let result = [];
array.forEach((obj, i) => {
let nameArray = obj.name.replace(/[\[\]']+/g, ' ').trim().split(' ');
let o = {};
o['id'] = parseInt(nameArray[0]);
o[nameArray[1]] = obj.value;
newArray.push(o);
});
for(let i = 0; i< newArray.length; i++) {
for(let j = i+1; j < newArray.length; j++) {
if(newArray[i].id === newArray[j].id) {
let o = {...newArray[i], ...newArray[j]};
result.push(o);`enter code here`
}
}
}
console.log('Final result', result);
Thanks for the input. I think my question needed to be more specific:
(1) Yes, they are always in order.
(2) My names of my input-tags in html appear to be an multidimensional array. This is not the case! I tried something, but it turned out to be for php.
I found the follow workaround:
function apiAdapter() {
var arrayToCopy = $("#formsteps").serializeArray();
var copiedArray = [];
for (let i = 0; i < arrayToCopy.length; i += 2) {
var id = arrayToCopy[i].name.slice(arrayToCopy[i].name.indexOf('[') + 1, arrayToCopy[i].name.indexOf(']'));
copiedArray.push({ "id": id, "apples": arrayToCopy[i].value, "melons": arrayToCopy[i + 1].value })
}
return copiedArray;
}
As I am new to JavaScript I always look for better solutions. So thanks again for your posts.
I set the data to a key called 'todo' in Local Storage.
The structure is like this.
key: todo
value : [{"text":"text1","idx":1},
{"text":"text2","idx":2},
{"text":"text4","idx":4}]
How to find the index of an object with idx = "4"?
For example, an object with idx = 1 has an index of 0.
key: todo
value : [{"text":"text1","idx":1} => index: 0
{"text":"text2","idx":2} => index: 1
{"text":"text4","idx":4}] => index: 2
Assuming that you've already parsed the JSON string from local storage (if not you can use JSON.parse()), you can use .findIndex() to get the index of an object with a given id:
const arr = [{
"text": "text1",
"idx": 1
}, {
"text": "text2",
"idx": 2
}, {
"text": "text4",
"idx": 4
}];
const search = 4;
const res = arr.findIndex(({idx}) => idx === search); // find index of object where idx is equal to search (4)
console.log(res); // 2
Use
todo.findIndex(elem => elem.idx === 4 )
I have problems in going through these two for loops, I need to get the same elements from the first array within the cycle, but the values are being repeated. I know that they are repeated depending on the data of the second array.
I tried to make comparisons but I could not get the result I want.
var array = [
{
grouper: 1
},
{
grouper: 2
},
{
grouper: 3
},
{
grouper: 4
},
];
var array2 = [
{
value: 1,
grouper: 1,
status: 100
},
{
value: 2,
grouper: 2,
status: 100
},
{
value: 3,
grouper: 3,
status: 100
}
];
for(var i = 0; i<array.length; i++){
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
}
}
}
This is the result I want, I need all the groupers from the first array and the values from the second array:
1-1
2-2
3-3
4-
The grouper 4, does not have value, but I need to show it.
I need the second array because I'm going to compare with the data from the second array
I do not know if I am doing the process wrong. I hope you can help me.
You could simply track if there was a match (variable shown), and if there were not any, display a "half" line:
var array = [{grouper: 1},{grouper: 2},{grouper: 3},{grouper: 4},];
var array2 = [
{value: 1, grouper: 1, status: 100},
{value: 2, grouper: 2, status: 100},
{value: 3, grouper: 3, status: 100}
];
for(var i = 0; i<array.length; i++){
var shown=false;
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
shown=true;
}
}
if(!shown){
console.log(array[i].grouper+"-");
}
}
First of all, with the example you provided I believe you want to get back:
1,2,3
There is no 4th object inside of array2, so your conditional (array2[j].grouper == array[i].grouper will never evaluate to true.
The question here is whether you are always comparing the same indexes? In this example, you're comparing array[0] to array2[0] to see if grouper in array equals grouper in array2... that's it????
In that case you just do one loop:
for (var i = 0; i < array.length; i++) {
if (array[i].grouper == array2[i].grouper) {
console.log(array[i].grouper+'-'+array2[j].value);
}
}
#FabianSierra ... with your provided example one just needs to handle the not fulfilled if clause/condition in the most inner loop.
A more generic approach additionally might take into account changing field names (keys). Thus a function and Array.reduce / Array.find based approach provides better code reuse. An example implementation then might look similar to that ...
var array = [{ // in order.
grouper: 1
}, {
grouper: 2
}, {
grouper: 3
}, {
grouper: 4
}];
var array2 = [{ // not in the order similar to `array`.
value: 22,
grouper: 2,
status: 200
}, {
value: 33,
grouper: 3,
status: 300
}, {
value: 11,
grouper: 1,
status: 100
}];
function collectRelatedItemValuesByKeys(collector, item) {
var sourceKey = collector.sourceKey;
var targetKey = collector.targetKey;
var targetList = collector.targetList;
var resultList = collector.result;
var sourceValue = item[sourceKey];
var targetValue;
var relatedItem = targetList.find(function (targetItem) {
return (targetItem[sourceKey] === sourceValue);
});
if (typeof relatedItem !== 'undefined') {
targetValue = relatedItem[targetKey];
} else if (typeof targetValue === 'undefined') {
targetValue = ''; // `relatedItem` does not exist.
}
resultList.push([sourceValue, targetValue].join('-'));
return collector;
}
var resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'value',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'status',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
.as-console-wrapper { max-height: 100%!important; top: 0; }