Array of array to object - javascript - javascript

I am looping to convert the array of array to object, but the final object has only the last item in the object. I am getting confused because you cant push in an object like array, and the number of loop is getting me frustrated. need help
here is the JSbin : http://jsbin.com/torawovicu/edit?js,console
Also how to get the object the same order as the array?
this is what the result should look like:
var newResult =
[
{itemcode: 1, item: 'Pen', 'cashier' : 'Sam'},
{itemcode: 2, item: 'Eraser', 'cashier' : 'Kim'}
]
Here is my code
var list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
]
//console.log(people.length);
function result(array) {
var newObj = {};
var newArr = [];
for (var x in array) {
//console.log(array[x])
var item = array[x];
for (var y in item) {
var itemSingle = item[y]
//console.log(itemSingle);
for (i = 0; i < itemSingle.length; i = i + 2) {
newObj[itemSingle[i]] = itemSingle[i + 1];
}
}
}
return newObj;
}
console.log(result(list));

You can use Array.prototype.map and Array.prototype.reduce to get the desired result like this:
var list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
];
function result(arr) {
return arr.map(function(sub) {
return sub.reduce(function(acc, e) {
acc[e[0]] = e[1];
return acc;
}, {});
})
}
console.log(result(list));
Note: you can't relly on the order of the object poperties.

You have to use one loop to iterate over main array and then run loops to iterate over each array item (which also is an array) to construct object with properties you need. You can use map as main loop to return new array with items constructed inside each iteration. To construct those items you can use forEach:
var list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
];
function result(array) {
let newArray = array.map(function(nestedArray) {
let obj = {};
nestedArray.forEach(function(item) {
obj[item[0]] = item[1];
});
return obj;
});
return newArray;
}
console.log(result(list));

There are two problems.
First, you're never adding the objects to the array or returning the array, you're just returning the object.
Second, you're using the same object each time through the loop, just replacing its properties. You need to create a new object each time, and then add it to the array.
It's also not a good idea to use for-in to iterate an array, use a numeric for loop (or the Array.prototype.forEach() function). See Why is using "for...in" with array iteration a bad idea?
var list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
]
//console.log(people.length);
function result(array) {
var newArr = [];
for (var x = 0; x < array.length; x++) {
var newObj = {};
var item = array[x];
for (var y = 0; y < item.length; y++) {
var itemSingle = item[y];
for (var i = 0; i < itemSingle.length; i+=2) {
newObj[itemSingle[i]] = itemSingle[i + 1];
}
}
newArr.push(newObj);
}
return newArr;
}
console.log(result(list));

You can do it with a single line:
const newResult = list.map(a => a.map(([k,v]) => ({[k]: v})));
const show = msg => {console.log(JSON.stringify(msg));};
const list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
];
const newResult = list.map(a => a.map(([k,v]) => ({[k]: v})));
show(newResult);

Your question could possibly be addressed by using a relatively recent feature in JavaScript: map objects.
Note that when you have an array of indeterminate length where each element is itself an array that is two elements long, you can convert the outer array into a map object instead of just a plain object. e.g. const newMapObj = new Map([['a', 1], ['b', 2]]);. Entering that into a terminal and then checking console.log(newMapObj) produces the following: Map { 'a' => 1, 'b' => 2 }. In your example, you could do this with each of your two list elements/store items, i.e. you would end up with an array of 2 map objects.
Such map objects have some convenient features, such as get and has. Some people also find them frustrating because of e.g. a lack of some helpful methods used with, say, arrays, like, um, well, the map method. (Note that the map method on arrays and the map/Map data object type are two completely different things. I know, it's confusing.)
The code snippet below creates an array of such map objects, one for each outer array element (i.e. one for each store 'item'), with one simple line:
const newResult = list.map(a => new Map(a));
Unfortunately, at this point in time at least, the code snippet tool here on Stack Exchange doesn't allow us to simply show the map object using console.log the way you can with, say, a plain object or an array. As a 2nd best substitute, the code snippet below logs out some of the results of using the map objects, just to demonstrate that the map objects were in fact created.
When I do the same thing in a Mac terminal (i.e. define list as the nested arrays in your question and then calculate newResult as above), console.log(newResult) shows the following:
[ Map { 'itemCode' => 1, 'item' => 'Pen', 'cashier' => 'Sam' },
Map { 'itemCode' => 2, 'item' => 'Eraser', 'cashier' => 'Kim' } ]
In other words, it is an array of map objects instead of an array of objects.
If you're interested in this recent JavaScript feature, you should check out the MDN documentation on the Map data object.
Whether you really want to use map objects or plain objects depends on your use case. The MDN documentation linked above has a short section to help you determine whether you want to use map objects or plain objects.
const list = [
[
['itemCode', 1],
['item', 'Pen'],
['cashier', 'Sam']
],
[
['itemCode', 2],
['item', 'Eraser'],
['cashier', 'Kim']
]
];
const newResult = list.map(a => new Map(a));
console.log('The name for the 1st item is:', newResult[0].get('item'));
console.log('The cashier for the 2nd item is:', newResult[1].get('cashier'));

You will have to use 2 dimensional array for that, first you have to create one for comlumn and second for row, in example i have shown in comulmn i have added the name, and in row i have added occupation, let's code :-
data = new Array(5)
info = [0] = new Array(2)
name [0][0] = "Tom"
occu [0][1] = "Worker"
info [1] = new Array(2)
name [1][0] = "Beryl"
occu [1][1] = "engineer"
info [2] = new Array(2)
name [2][0] = "Ann"
occu [2][1] = "surgeon"
info [3] = new Array(2)
occu [3][0] = "Bill"
name [3][1] = "taxman"
info [4] = new Array(2)
name [4][0] = "Myrtal"
occu [4][1] = "bank robber"

Related

What is the best way to check multidimensional array in typescript or javascript to detect duplicate values?

I have two dimensional array like below:
array = [ [ 1, 1 ], [ 1, 2 ], [ 1, 1 ], [ 2, 3 ] ]
I want to compare value in array index to see if they have duplicate values. For example
array[0] = [1,1];
array[1] = [1,2];
array[2] = [1,1];
We can see that value at index 0 and 2 are same that is [1,1]. So, in that case I want to have true flag. What is the most efficient way to do it? or What are different ways to do it? Any kind of suggestion or help would be great with bit of explanation. Thanks in advance.
You can achieve it by convert the inner array elements into a string just for the comparison purpose.
Demo :
const arr = [[ 1, 1 ], [ 1, 2 ], [ 1, 1 ], [ 2, 3 ]];
const stringConversion = arr.map((item) => JSON.stringify(item))
const duplicateElements = stringConversion.filter((item, index) => stringConversion.indexOf(item) !== index)
console.log(duplicateElements.length ? true : false);
So, what I think you can do is:
Cycle every element of the multidimensional array.
Then check if the two element are the same by accessing the "row" with the index 0 and index 1
I think you can use different way to loop the array, this is what I tried:
// DECLARATIONS
array = [[ 1, 1 ], [ 1, 2 ], [ 1, 1 ], [ 2, 3 ]];
// LOOPING THE ARRAY
for (row of array)
{
// RETURN TO CONSOLE OR WHATEVER THE BOOLEAN VALUE
console.log(row[0] == row[1]);
}
String to convert array to a one-dimensional array of strings and some to check if any element is duplicated:
const arr = [[1, 1], [1, 2], [1, 1], [2, 3]];
const result = arr.map(String).some((v, i, a) => a.indexOf(v) !== i);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to create a list of objects in JavaScript

I have an array of pairs of values somewhat like this:
let myarr = [[1, 'a'],
[2, 'b'],
[3, 'c']]
and one like this:
let otherArr = [5,6,7]
and I would like to convert them to an object which would be of the form:
{
"data":[
{
"id":5,
"pair":[
1,
"a"
]
},
{
"id":6,
"pair":[
2,
"b"
]
},
{
"id":7,
"pair":[
3,
"c"
]
}
]
}
As a first attempt
I tried to use a for loop and tried to create a list of the pair keys like this
for (let pair = 0; pair < myarr.length; pair++) {
myobj[pair].pair = myarr[pair]
and I get an error stating TypeError: Cannot set property 'pair' of undefined
Is there a efficient way to create a object like the example above
Thanks in advance
The reason your for loop fails is because you need to instantiate an object before you can set properties on it. For example, you could use Array.push to iterate over your array and create new objects at each index.
const myobj = { data: [] };
for (let index = 0; index < myarr.length; index++) {
myobj.data.push({ pair: myarr[index], id: otherArr[index]})
}
A shorter way to write the above, assuming that myarra and otherArr will always have the same length, would be to use Array.map to iterate over your first array and return a new one of the same length.
const myobj = {
data: myArra.map((pair, index) => ({ pair, id: otherArr[index] })
}
Try this :
let otherArr = [5,6,7];
let myarr = [[1, 'a'], [2, 'b'], [3, 'c']];
let obj = { "data":[] };
otherArr.map((item, index) => {
obj.data.push({
"id": item,
"pair": myarr[index]
})
});
console.log(obj);
You can do something like below
let myarr = [[1, 'a'],
[2, 'b'],
[3, 'c']];
let otherArr = [5,6,7];
let data = myarr.map((i,idx) => {
return {
"id": otherArr[idx],
"pair": i
};
});
console.log({data});

How to name Values in array by values in different array?

I have two arrays:
The first contains unique names of fields in a nested array:
[0][0]:Name1
[0][1]:Name2
[0][2]:Name3
etc.
The second contains multiple items with values in a nested array like this:
[0][0] XYZ
[0][1] XYZA
[0][2] XYZ2
[1][0] XYZaa
[1][1] XYZas
[1][2] XYA
etc
What I want to do is to merge it and name it in this way:
[0] Name1: XYZ
[0] Name2: XYZA
[0] Name3: XYZ2
[1] Name1: XYZaa
[1] Name2: XYZas
[1] Name3: XYA
To achieve this I first attempted the following:
var mergedArr = name.concat(data);
That works fine, however I believe I can also use lodash to get closer to what I want:
_.merge(name, data)
and should work fine too.
I was trying to name it by using
_.zipObject
Yet it doesn't work the way I would like
I was trying few options with zip, zipObject, yet non of it gave me expected output.
Edit1:
how I created arrays:
$("#T1020 tr").each(function(x, z){
name[x] = [];
$(this).children('th').each(function(xx, zz){
name[x][xx] = $(this).text();
});
})
$("#T1020 tr").each(function(i, v){
data[i] = [];
$(this).children('td').each(function(ii, vv){
data[i][ii] = $(this).text();
});
})
If I understand your question correctly, you're wanting to zip array1 and array2 into a single array where:
each item of the result array is an object
the keys of each object are values of array1[0], and
the values of each key corresponding nested array of array2
To produce the following:
[
{
"name1": "xyz",
"name2": "xyza",
"name3": "xyz2"
},
{
"name1": "xyzaa",
"name2": "xyzas",
"name3": "xya"
}
]
This can be achieved without lodash; first map each item of array2 by a function where array1[0] is reduced to an object. The reduced object is composed by a key that is the current reduce item, and a value that is taken from the indexed value of the current map item:
const array1 = [
['name1', 'name2', 'name3']
]
const array2 = [
['xyz', 'xyza', 'xyz2'],
['xyzaa', 'xyzas', 'xya']
]
const result = array2.map((item) => {
/* Reduce items of array1[0] to an object
that corresponds to current item of array2 */
return array1[0].reduce((obj, value, index) => {
return { ...obj,
[value]: item[index]
};
}, {});
});
console.log(JSON.stringify(result, null, ' '));
Iterate the values (your array2) and take the sub-array from the keys (array) using the current index and the % operator. This will ensure that if that the keys are taken in a cyclic way (see example with keys2 and values2). Convert to object with _.zipObject:
const fn = (keys, values) => values.map((v, i) => _.zipObject(keys[i % keys.length], v))
const keys1 = [['name1', 'name2', 'name3']]
const values1 = [['xyz', 'xyza', 'xyz2'], ['xyzaa', 'xyzas', 'xya']]
const keys2 = [['name1', 'name2', 'name3'], ['name11', 'name12', 'name13']]
const values2 = [['xyz', 'xyza', 'xyz2'], ['xyzaa', 'xyzas', 'xya'], ['abc', 'def', 'hij']]
console.log(fn(keys1, values1))
console.log(fn(keys2, values2))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

adding copy of array to another array

I am trying to add a copy of an array to another array with array.slice(), but when I update the original, it updates the copy that I added. How can I add a copy that isn't altered when the original is altered?
I've tried using result.unshift[...curRow], and result.unshift(curRow.slice()) when I add
function game(n) {
var result = [];
let row1=[[1, 2]];
for (var i=1;i<n;i++){
var cur = row1[i];
var prev = row1[i - 1];
row1.push([prev[0] + 1, prev[1] + 1]);
}
result.push(row1.slice());
let curRow = row1.slice();
for (var i=1;i<n;i++){
for (var j = 0; j<curRow.length ;j++){
curRow[j][1]++;
}
result.unshift(curRow.slice());
console.log('curRow =',curRow);
console.log('result = ', result)
}
console.log('result = ', result)
return result
}
game(3);
This is my current output:
'result ='[ [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ] ]
'result = '[ [ [ 1, 3 ], [ 2, 4 ], [ 3, 5 ] ], [ [ 1, 3 ], [ 2, 4 ], [ 3, 5 ] ] ]
'result = '[ [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ], [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ], [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ] ]
I want the result array to contain each iteration of the curRow array, instead of just having copies of the latest one.
In JavaScript, objects/arrays, also known as non-primitive types, are given a reference, rather than value. Therefore, this particular reference points to the object's location in the memory. That variable you are working with has a 'reference' rather than containing an actual 'value'. This is why it is mutated when you use it on the game() function.
To work with that, you should create a shallow copy of that array, before making any manipulation/mutation to it.
const copy = originalArray.map(element => ({...element}));
Now, all changes to the copy array will not be applied to originalArray.
Because in Javascript Arrays are handled by reference, when you reasign an array to a new variable, the new variable only holds a reference to the original array. Any alteration on the original array will be reflected in any of its instances/references (beucause they are essentially the same object).
Since the ES6 version of the standard we have Array.from() to perform copies or duplicates of the contents of an Array.
It's my favorite way to go, is fast, safe and readable.
The Array.from() method creates a new, shallow-copied Array instance from an array-like or iterable object. Extended documentation here
Check the example :
let a = [1,2,3,4,5];
let b = Array.from(a);
// modify first array to test
a[0] = 666;
// output second array to check
console.log(b)
// [1,2,3,4,5] OK!
you can use this concept:
firstArray=firstArray.concat(...secondArray);

find unique entries inside a multidimensional javascript array, order important dependent on level

What would be the most elegant solution to find all unique first level entries inside a multidimensional javascript array? There is only one important rule: the order of the entries is important only on the first level, but not important on the second level
For example, for the following array the script should return 4 unique entries (the first, the third, the fourth and the fifth):
[
[ [],[22],[1,13,17],[12],[] ],
[ [],[22],[17,13,1],[12],[] ],
[ [],[12],[1,13,17],[22],[] ],
[ [11],[12],[13],[14],[15] ],
[ [15],[14],[13],[12],[11] ]
]
PS. jQuery can be used as well.
First of all, here is a working JSFiddle for you to play around with: http://jsfiddle.net/missyalyssi/ro8o94nk/
Given an input array the function findUnique will return an array containing items that are unique according to your definition. So, for example:
[[8],[1,2,3],[9]] is a duplicate of [[8], [3,1,2], [9]] but it is not a duplicate of [[9], [3,1,2], [8]]
My main focus when writing this was to make it easy to read and understand.
function findUnique(input) {
let found = [];
let uniqueEls = new Set();
let hasDup = true;
for (let element of input) {
hasDup = found.length &&
found.every((el) => {return deepEqualsNaive(el, element)});
if (hasDup) {
uniqueEls.delete(element);
continue;
}
found.push(element);
uniqueEls.add(element);
}
return [...uniqueEls];
}
This function uses deepEqualsNaive to determine if two arrays are equal. Since object equality in javascript means that the arrays would point to the same memory location we need to build our own function to return true for what we are calling equal. Here, by equal we mean that they have the same elements even though they are not pointing to the same memory location, or appearing in the same order.
I have written this function recursively for readability I do not know the context that you are using this in. If you could overflow the stack then use an iterative version.
Here are some example inputs and what we would expect:
deepEqualsNaive([ [],[22],[1,13,17],[12],[] ], [ [],[22],[17,13,1],[12],[] ]) => true
deepEqualsNaive([ [],[22],[17,13,1],[12],[] ], [ [],[12],[1,13,17],[22],[] ]) => false
deepEqualsNaive([ [],[22],[1,13,17],[12],[] ], [ [],22,[17,13,1],[12],[] ]) => false
The function:
function deepEqualsNaive (input, clone) {
if (!Array.isArray(input) || !Array.isArray(clone)) return false;
if (input.length !== clone.length) return false;
var result = 0;
for (let elIdx = 0; elIdx < input.length; elIdx++) {
var tryDeep = true;
if (Array.isArray(input[elIdx])) tryDeep = deepEqualsNaive(input[elIdx], clone[elIdx]);
if (!tryDeep) return false;
result ^= input[elIdx];
result ^= clone[elIdx];
}
return result === 0;
}
If you're not all that worried about performance and just need something that works, you could use the constant depth you mentioned along with the string representation as a "fingerprint" of sorts (akin to Java's hashcode).
Then you use a Set to keep track of items you've not seen before, and add only those that are new.
function getUnique(rows) {
let unique = new Set();
let results = [];
for (let row of rows) {
// Fingerprint is the string representation of the row,
// with the inner-level sorted (as order doesn't matter).
// E.g., fingerprint of [ [8], [3, 2, 1], [9] ] is '[[8],[1,2,3],[9]]'
let fingerprint = JSON.stringify(row.map((cells) => {
return cells.concat().sort(); // Use concat to avoid sorting in place.
}));
// If we haven't seen this fingerprint before,
// add to the filter and the results list.
if (!unique.has(fingerprint)) {
unique.add(fingerprint);
results.push(row);
}
}
return results;
}
This, for example, will come up with...
> x = [
... [ [8], [3, 2, 1], [9] ],
... [ [7], [8, 3, 9], [1, 2] ],
... [ [8], [1, 2, 3], [9] ],
... ];
> getUnique(x);
[ [ [ 8 ], [ 3, 2, 1 ], [ 9 ] ],
[ [ 7 ], [ 8, 3, 9 ], [ 1, 2 ] ] ]
Obviously if your inner values are non-primitives (objects, arrays, etc) then this will fall over, but if you're dealing with numbers like your example, it should be fine.
If it's ok to have reference to the original array 'records' and inner arrays (that is, no deep copy), you can use something like:
function distinct(arr){
const res =[], //array with results
cmpArr = (a1,a2) => a1.length===a2.length && a1.every((i,ind) => a2[ind] === i),
cmpRec = (a1,a2) => [1,2,3].every(i=> cmpArr(a1[i],a2[i])); //compare 'records' for indices 1,2 and 3
for(let subarr of arr){
subarr[2].sort(); //NB, this alters the source array. If this is not allowed, a work around can be created
if(!res.some(r => cmpRec(r,subarr))) //check if 'res' doesn't have an entry , based on the cmpRec function
res.push(subarr);
}
return res;
}
//test:
let input = [
[ [],[22],[1,13,17],[12],[] ],
[ [],[22],[17,13,1],[12],[] ],
[ [],[12],[1,13,17],[22],[] ],
[ [11],[12],[13],[14],[15] ],
[ [15],[14],[13],[12],[11] ]
];
console.log(distinct(input).map(JSON.stringify));

Categories

Resources