I have an object that contains a key and an array with some values inside of it.
var obj1 = {
'key': '1',
'values': ['a', 'b', 'c']
}
var obj2 = {
'key': '10',
'values': ['a', 'b']
}
I want to split this in other objects for each value in my values array to result something like this:
obj1 = 'key': '1', 'value':'a', 'index': '0';
obj2 = 'key': '1', 'value':'b', 'index': '1';
obj3 = 'key': '1', 'value':'c', 'index': '2';
obj4 = 'key': '10', 'value': 'a', 'index': '0';
obj5 = 'key': '10', 'value': 'b', 'index': '1';
Any ideas to do this?
Try this example
var brief = function(obj) {
var tmp = [],
i = 0,
l = obj.values.length;
while (i < l)
tmp.push({
key: obj.key,
index: i,
value: obj.values[i++]
});
return tmp;
};
var obj1 = brief({
key: '1',
values: ['a', 'b', 'c']
});
var obj2 = brief({
key: '2',
values: ['a', 'c']
});
document.write("<pre>");
document.write(JSON.stringify(obj1));
document.write("<br/>");
document.write(JSON.stringify(obj2));
document.write("</pre>");
Friend, it would be something like:
tmp = [];
obj1.values.forEach(function (e, i) {
tmp.push({key: obj1.key, value: e, index: i})
});
console.log(tmp);
assuming that you want
obj1 =[ { key: '1', value:'a', index: '0' },
{ key: '1', value:'b', index: '1'},
{ key: '1', value:'c', index: '2' }]
try
function splitArray( obj )
{
var output = [];
var keyValue = obj.key;
var values = obj.values;
for ( var counter = 0; counter < values.length; counter++ )
{
output.push( {
key : keyValue,
value : values[ counter ],
index : counter
} );
}
return output;
}
console.log( splitArray( obj1 ) );
function getTransformedObjects(obj) {
var ans = [];
if (obj.values) {
obj.values.forEach(function(value, index) {
var temp = {
'key': obj.key,
'value': value,
'index': index
};
ans.push(temp);
})
}
return ans;
}
//for display purpose
// usage
var obj1 = {
key: '1',
values: ['a', 'b', 'c']
}
console.log(getTransformedObjects(obj1));
$('.old').html(JSON.stringify(obj1))
$('.new').html(JSON.stringify(getTransformedObjects(obj1)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div>old object</div>
<div class='old'></div>
<div>Trasnformed object</div>
<div class='new'></div>
Call the function passing the old object as parameter and get the array of objects in required format.
Related
Is there any simple solution (vanilla js or lodash) to filter collection by nested items count?
For example there is following grouped collection:
[
{
Items: ['a', 'b', 'c'],
Name: 'Group 1'
},
{
Items: ['d', 'e','f'],
Name: 'Group 2'
}
]
If I need to take 2 items it should return:
[
{
Items: ['a', 'b'],
Name: 'Group 1'
}
]
If I need to take 5 items it should return:
[
{
Items: ['a', 'b', 'c'],
Name: 'Group 1'
},
{
Items: ['d', 'e'],
Name: 'Group 2'
}
]
You need to iterate the items (for...of in this case), and count the number of items in the result + the current object items length.
If it's less or equal to the total wanted (n) you push the original object. If it's more, you slice the nested array, so it will include the difference.
If the current count is equal or more than n (or if the loop ends) return the result (res).
const fn = (arr, n, key) => {
let count = 0
const res = []
for(const o of arr) {
const len = o[key].length
res.push(count + len <= n ? o : { ...o, [key]: o[key].slice(0, n - count) })
count += len
if(count >= n) return res
}
return res
}
const arr = [{"Items":["a","b","c"],"Name":"Group 1"},{"Items":["d","e","f"],"Name":"Group 2"}]
console.log(fn(arr, 2, 'Items'))
console.log(fn(arr, 5, 'Items'))
console.log(fn(arr, 8, 'Items'))
My solution, maybe not perfect but it works :)
let array = [
{
Items: [
'a',
'b',
'c'
],
Name: 'Test1'
},
{
Items: [
'd',
'e',
'f'
],
Name: 'Test2'
}
];
let itemsCount = 5;
let filteredArray = [];
array.some(group => {
if (itemsCount <= 0) {
return true;
}
if (group.Items.length <= itemsCount) {
itemsCount -= group.Items.length;
} else {
group.Items = group.Items.slice(0, itemsCount);
itemsCount = 0;
}
filteredArray.push(group);
});
console.log(filteredArray);
I have 2 arrays and i'd like to filter one array with the other. E.g. if array1 includes any of the values in array2, they should be returned.
The two arrays are:
const array1 = [a, b, c, d]
The other array, which should be filtered where 'id' is equal to any of the values in array1 is:
const array2 = [
{
id: b
title: title1
},
{
id: d
title: title2
},
{
id: f
title: title3
}
]
The easiest way is to use two for-loops. Possible not the fastest approach.
res = [];
for (var i = 0;i<array1.length;i++) {
for (var j = 0;j<array2.length;j++) {
if (array1[i] == array2[j].id) {
res.push(array2[j]);
break;
}
}
}
You could use Array.prototype.filter() and Array.prototype.indexOf():
const array1 = ['a', 'b', 'c', 'd'];
const array2 = [{
id: 'b',
title: 'title1'
}, {
id: 'd',
title: 'title2'
}, {
id: 'f',
title: 'title3'
}];
const result = array2.filter(function(x){
return array1.indexOf(x.id) !== -1;
});
Adding this missing '', You can use filter and includes methods of Array.
const array1 = ['a', 'b', 'c', 'd'];
const array2 = [
{
id: 'b',
title: 'title1'
},
{
id: 'd',
title: 'title2'
},
{
id: 'f',
title: 'title3'
}
]
const result = array2.filter(({id}) => array1.includes(id));
console.log(result);
I want to dynamically create an object with key value pairs from an array of object. How can this be done?
const arr= [
{key: 'a', value: '1'},
{key: 'b', value: '2'},
{key: 'c', value: '3'},
];
The result should look like this:
const obj = {
a: '1',
b: '2',
c: '3',
};
I would use reduce function for that.
The agg is an aggregator which aggregate our final result.
The item is representing each element in the array.
const arr= [
{key: 'a', value: '1'},
{key: 'b', value: '2'},
{key: 'c', value: '3'},
];
const result = arr.reduce((agg, item) => {
agg[item.key] = item.value
return agg
}, {})
console.log(result)
// { a: '1', b: '2', c: '3' }
The reduce() method executes a reducer function (that you provide) on each member of the array resulting in a single output value.
simple forEach will do the job
const arr= [
{key: 'a', value: '1'},
{key: 'b', value: '2'},
{key: 'c', value: '3'},
];
const obj = {};
arr.forEach(v=>{
obj[v.key] = v.value;
});
console.log(obj);
Very easy, probably a duplicate.
const arr= [
{key: 'a', value: '1'},
{key: 'b', value: '2'},
{key: 'c', value: '3'},
];
const obj = {};
for (let i = 0; i < arr.length; ++i) {
obj[arr[i].key] = arr[i].value
}
console.log(obj);
function parse(input){
return input.reduce(function(o,i){
o[i.key] = i.value;
return o;
},{});
}
Use Array.forEach() and the square brackets syntax to set the properties of the new object.
const arr = [
{key: 'a', value: '1'},
{key: 'b', value: '2'},
{key: 'c', value: '3'},
];
const obj = {};
arr.forEach(({key, value}) => obj[key] = value);
console.log(obj);
You can simply create an empty object and then create new properties on the fly, while iterating an array.
let obj = {};
for(let i = 0; i < arr.length; i++) {
obj[arr[i].key] = obj[i].value;
}
Example object array:
[{
id: 'a',
beforeId: null
}, {
id: 'b',
beforeId: 'c'
}, {
id: 'c',
beforeId: 'a'
}, {
id: 'd',
beforeId: 'b'
}]
Output order: d-b-c-a; each element sorted relative to each other element based on its beforeId property.
I could make a temporary array and sort the above array. Is sorting possible with array.sort?
You could build an object with the relations and generate the result by using the object with beforeId: null and unshift all objects for the result array.
The next object is the one with the actual val as key.
Complexity: O(2n).
function chain(array) {
var o = {}, pointer = null, result = [];
array.forEach(a => o[a.beforeId] = a);
while (o[pointer]) {
result.unshift(o[pointer]);
pointer = o[pointer].val;
}
return result;
}
var data = [{ val: 'a', beforeId: null }, { val: 'b', beforeId: 'c' }, { val: 'c', beforeId: 'a' }, { val: 'd', beforeId: 'b' }];
console.log(chain(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is a terribly inefficient and naïve algorithm, but it works:
const array = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
// find the last element
const result = [array.find(i => i.beforeId === null)];
while (result.length < array.length) {
// find the element before the first element and prepend it
result.unshift(array.find(i => i.beforeId == result[0].id));
}
console.log(result);
Is sorting possible with array.sort?
sure, with a helper function:
graph = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
let isBefore = (x, y) => {
for (let {id, beforeId} of graph) {
if (id === x)
return (beforeId === y) || isBefore(beforeId, y);
}
return false;
};
graph.sort((x, y) => x === y ? 0 : (isBefore(x.id, y.id) ? -1 : +1))
console.log(graph);
isBefore returns true if x is before y immediately or transitively.
For generic, non-linear topological sorting see https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
UPD: As seen here, this turned out to be horribly inefficient, because sort involves many unnecessary comparisons. Here's the fastest (so far) version:
function sort(array) {
let o = {}, res = [], len = array.length;
for (let i = 0; i < len; i++)
o[array[i].beforeId] = array[i];
for (let i = len - 1, p = null; i >= 0; i--) {
res[i] = o[p];
p = o[p].id;
}
return res;
}
which is the #Nina's idea, optimized for speed.
You may try this approach :
// order(null, vals, []) = ["d", "b", "c", "a"]
function order(beforeId, vals, result){
var id = beforeId || null;
var before = vals.filter(function(val){
return val.beforeId === id
});
if (before.length === 0) return result;
return order(before[0].val,
vals,
[before[0].val].concat(result));
}
If I have a result like this:
result = [
{ '0': 'grade', A: 'name', b1: 'number' },
{ '1': 'grade', B: 'name', b2: 'number' },
{ '2': 'grade', C: 'name', b3: 'number' }
];
How can I produce :
result = [
{ A: '0', b1: '0' },
{ B: '1', b2: '1' },
{ C: '2', b3: '2' }
];
I want to pass the analogous grade instead of name and number.
The order of keys in an object is not guaranteed. This means simply getting a key array and looping through them or accessing them by index will not work. You could make this work be detecting numeric and non-numeric keys like so:
result = [
{ '0': 'grade', A: 'name', b1: 'number' },
{ '1': 'grade', B: 'name', b2: 'number' },
{ '2': 'grade', C: 'name', b3: 'number' }
];
result.forEach(item => {
var keys = Object.keys(item);
var numericKey = keys.find(key => !isNaN(key));
var nonNumericKeys = keys.filter(key => isNaN(key));
nonNumericKeys.forEach(nonNumKey => item[nonNumKey] = numericKey);
delete item[numericKey];
});
Assuming the b3: '1' part is a typo... the following should work.
var input = [
{ '0': 'grade', A: 'name', b1: 'number' },
{ '1': 'grade', B: 'name', b2: 'number' },
{ '2': 'grade', C: 'name', b3: 'number' }
];
function reverseMap(obj){
var newObj = {};
var keys = Object.keys(obj);
for(var i=0; i<keys.length; i++){
var k = keys[i];
var v = obj[k];
newObj[v] = k;
}
return newObj;
}
var output = [];
for(var i=0; i<input.length; i++){
var reverseObj = reverseMap(input[i]);
var outputObj = {};
var number = reverseObj.grade;
outputObj[reverseObj.name] = number;
outputObj[reverseObj.number] = number;
output.push(outputObj);
}
console.log(output);
With ES6 you can use the for of loop and Objects.keys for this task:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/let
let newResult = [];
for(let r of result) {
let keys = Object.keys(r);
let obj = {};
for(let key of keys) {
if(/\d/.test(key)) { var value = key; }
else if(/\w/.test(key)) { var key1 = key; }
else if(/\d/.test(key)) { var key2 = key; }
}
obj[key1] = value;
obj[key2] = value;
newResult.push(obj);
}
return newResult;