convert array into object using underscore only - javascript

I am learning underscore now and found a task for it I need help with .. I have an array with object looking like this
[
// ...
{
"type": "presence",
"params": {
"interval": 15,
"foo": "something",
"link": {
"fp_type": "1",
"fp_ext_id": "2"
},
},
{
"type": "bar",
"params": {
"interval": 30,
"foo": "foo",
"link": {
"fp_type": "2",
"fp_ext_id": "3"
},
},
},
// ...
]
The task is using underscore only to convert this array items to an object where the
the key is the items type and the value are its params, i.e.:
{
// ...
"presence": {
"interval": 15,
"foo": "something",
"link": {
"fp_type": "1",
"fp_ext_id": "2"
},
},
"bar": {
"interval": 30,
"foo": "foo",
"link": {
"fp_type": "2",
"fp_ext_id": "3"
},
// ...
}

You can do it this way:
var x = [
{
"type": "presence",
"params": {
"interval": 15,
"foo": "something",
"link": {
"fp_type": "sponsor",
"fp_ext_id": "spotme"
},
},
},
{
"type": "bar",
"params": {
"interval": 30,
"foo": "foo",
"link": {
"fp_type": "2",
"fp_ext_id": "3"
},
},
}
];
var y = _.map(x, function(i) {
let obj = {};
obj[i.type] = i.params;
return obj;
});
//console.log(y);
var result = y.reduce(function(obj,item) {
obj[_.keys(item)[0]] = _.values(item)[0];
return obj;
}, {});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
DEMO

Related

JavaScript — Split an array like a string

Is it possible to split an array into smaller arrays each time a specific value is found? In this case, every time type equals "divider".
Input:
[
{
"type": "type-a",
"name": "Foo"
},
{
"type": "type-b",
"name": "Foo"
},
{
"type": "type-c",
"name": "Foo"
},
{
"type": "divider",
"name": "Foo"
},
{
"type": "type-b",
"name": "Foo"
},
{
"type": "type-b",
"name": "Foo"
},
{
"type": "divider",
"name": "Foo"
},
{
"type": "type-c",
"name": "Foo"
}
]
Desired output:
[
[
{
"type": "type-a",
"name": "Foo"
},
{
"type": "type-b",
"name": "Foo"
},
{
"type": "type-c",
"name": "Foo"
}
],
[
{
"type": "type-b",
"name": "Foo"
},
{
"type": "type-b",
"name": "Foo"
}
],
[
{
"type": "type-c",
"name": "Foo"
}
]
]
This should work
const arr = [{ "type": "type-a", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "type-c", "name": "Foo" }, { "type": "divider", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "divider", "name": "Foo" }, { "type": "type-c", "name": "Foo" }];
function divide(container, divider) {
const final = [];
let tmp = new Array();
for (let item of container) {
if (item.type === divider) {
final.push(tmp);
tmp = new Array();
}
item.type !== divider && tmp.push(item)
}
tmp.length > 0 && final.push(tmp)
return final;
}
const res = divide(arr, 'divider');
console.log(res)
You can make use of reduce here as:
const arr = [{ "type": "type-a", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "type-c", "name": "Foo" }, { "type": "divider", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "type-b", "name": "Foo" }, { "type": "divider", "name": "Foo" }, { "type": "type-c", "name": "Foo" }];
const temp = [];
const result = arr.reduce((acc, curr) => {
if (curr.type === 'divider') {
acc.push([...temp]);
temp.length = 0;
} else {
temp.push(curr);
}
return acc;
}, []);
if (temp.length) result.push([...temp]);
console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this.
Search each object of the array and till you find the divider one, push all the objects into another array.
If divider is found, then increment the index, ignore this object and continue.
let arr=[{"type":"type-a","name":"Foo"},{"type":"type-b","name":"Foo"},{"type":"type-c","name":"Foo"},{"type":"divider","name":"Foo"},{"type":"type-b","name":"Foo"},{"type":"type-b","name":"Foo"},{"type":"divider","name":"Foo"},{"type":"type-c","name":"Foo"}]
let finalArr = []
let currentIndex = 0;
for (let obj of arr) {
if (obj.type === 'divider') {
currentIndex++;
} else {
(finalArr[currentIndex] = finalArr[currentIndex] || []).push(obj);
}
}
console.log(finalArr)
Here's a curried recursive function:
The first parameter is a predicate function that takes an element and decides whether that element is a delimiter. Then it takes an array and splits it into chunks. Each chunk contains the elements in between (but excluding) a delimiter element.
const splitBy = pred => function loop([x, ...xs], ret = [[]]) {
if (x == null) return ret;
if (pred(x)) ret.push([]);
else ret[ret.length-1].push(x);
return loop(xs, ret);
}
const isDivider = x => x.type == 'divider';
const splitByDivider = splitBy(isDivider);
splitByDivider([ { "type": "type-a" , "name": "Foo" }
, { "type": "type-b" , "name": "Foo" }
, { "type": "type-c" , "name": "Foo" }
, { "type": "divider", "name": "Foo" }
, { "type": "type-b" , "name": "Foo" }
, { "type": "type-b" , "name": "Foo" }
, { "type": "divider", "name": "Foo" }
, { "type": "type-c" , "name": "Foo" }]);
//=> [ [ { "type": "type-a", "name": "Foo" }
//=> , { "type": "type-b", "name": "Foo" }
//=> , { "type": "type-c", "name": "Foo" } ]
//=> , [ { "type": "type-b", "name": "Foo" }
//=> , { "type": "type-b", "name": "Foo" } ]
//=> , [ { "type": "type-c", "name": "Foo" } ]]

Remove item from json and edit remaining items - nodejs/firebase function

So I'm trying to update a json, after deleting an item using firebase .delete().
This is the json before delete
"data": [
{
"position": "3",
"name": "foo"
},
{
"name": "bar",
"position": "1"
},
{
"name": "deleteMe",
"position": "2"
},
{
"name": "somethingElse",
"position": "4"
}
]
and this is after:
"data": [
{
"position": "3",
"name": "foo"
},
{
"name": "bar",
"position": "1"
},
{
"name": "somethingElse",
"position": "4"
}
]
now all I have to do is reorder foo and somethingElse items positions from #3 to #2 and #4 to #3.
How can I do this?
EDIT:
This is the output I want:
"data": [
{
"position": "2",
"name": "foo"
},
{
"name": "bar",
"position": "1"
},
{
"name": "somethingElse",
"position": "3"
}
]
Use Array.prototype.map
var obj = {
data: [
{
position: "2",
name: "foo"
},
{
name: "bar",
position: "1"
},
{
name: "somethingElse",
position: "3"
}
]
};
var output =
obj.data.map((o, i) => {
o["position"] = "" + (i + 1);
return o;
});
console.log(output);

Flatten an object using lodash

I have below this nested object
I need to create an array using this object containing keys. And if keys are object then it should use .dot syntax. and if it is an array then it should give me key.0.keyName. Is it possible to do so?
Output
[
"AllowIPNPayment",
"AllowOnlinePayment",
"MetaData.CreateTime",
"MetaData.LastUpdatedTime",
"CustomField.0.DefinitionId",
"CustomField.0.Name",
"CustomField.0.Type",
...
]
What I have tried is just ugly and does give me expected result. If it is possible with more concise way.
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
let object = {}
for (let k in invoiceObject) {
if (typeof invoiceObject[k] === "object") {
object[k] = {};
for (let l in invoiceObject[k]) {
object[k][l] = "";
}
} else if (typeof invoiceObject[k] === "array") {
object[k] = [];
for (let l in invoiceObject[k][0]) {
object[k][l] = "";
}
} else {
object[k] = "";
}
}
console.log(object)
You can create a recursive function (getSchema) that checks if a value (val) is an object (arrays included), iterate it with _.flatMap(), and collects the keys until it hits a value which is not an object. It then joins the collected keys and returns the string.
const getSchema = (val, keys = []) =>
_.isObject(val) ? // if it's an object or array
_.flatMap(val, (v, k) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Without lodash, the main change is to use Object.entries() to get an array of [key, value] pairs, since Array.flatMap() can't iterate objects:
const getSchema = (val, keys = []) =>
typeof val === 'object' && val !== null ? // if it's an object or array
Object.entries(val) // get [key, value] pairs of object/array
.flatMap(([k, v]) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
inspired by the answer given in this post and understanding you just want to get the property-names, not values, you could do it like this. sorry, this uses plain javascript.
function flattenObjectToKeyArray(ob) {
var toReturn = [];
for (var prop in ob) {
if (!ob.hasOwnProperty(prop)) continue;
if ((typeof ob[prop]) == 'object' && ob[prop] !== null) {
var flatObject = flattenObjectToKeyArray(ob[prop]);
for (var idx = 0; idx < flatObject.length; idx++) {
toReturn.push(prop + '.' + flatObject[idx]);
}
} else {
toReturn.push(prop);
}
}
return toReturn;
}
You could solve this with a recursive function. The function below keeps track of the current keys, and joins them as soon as an end point is reached (a non-object or empty object/array).
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 };
function getDotKeys(item, keys = []) {
const isObject = item && typeof item == "object";
if (!isObject) return Array.of(keys.join("."));
const pairs = Array.isArray(item)
? item.map((value, index) => [index, value])
: Object.entries(item);
const isEmpty = !pairs.length;
if (isEmpty) return Array.of(keys.join("."));
const result = [];
for (const [key, value] of pairs) {
const dotKeys = getDotKeys(value, [...keys, key]);
result.push(...dotKeys);
}
return result;
}
console.log(getDotKeys(invoiceObject));
This does produce a different result than what you have in your question, since your solution stops at the second level for objects and third level for arrays. This solution also includes more then only index 0.

How to remove all 'map' properties from my array

From this array:
[{
"map": {
"name": "2",
"y": 2
}
}, {
"map": {
"name": "4",
"y": 17494
}
}, {
"map": {
"name": "3",
"y": 2
}
}, {
"map": {
"name": "1",
"y": 1
}
}]
I want this data structure:
[{
"name": "2",
"y": 2
}, {
"name": "4",
"y": 17494
}, {
"name": "3",
"y": 2
}, {
"name": "1",
"y": 1
}]
How can I do this?
Use JavaScript mapping:
let json = [{
"map": {
"name": "2",
"y": 2
}
}, {
"map": {
"name": "4",
"y": 17494
}
}, {
"map": {
"name": "3",
"y": 2
}
}, {
"map": {
"name": "1",
"y": 1
}
}];
let result = json.map(item => item.map);
result.forEach(i => console.log(i));
Above code prints:
{name: "2", y: 2}
{name: "4", y: 17494}
{name: "3", y: 2}
{name: "1", y: 1}
See:
Array.map
Use Array.prototype.reduce()
let input=[{
"map": {
"name": "2",
"y": 2
}
}, {
"map": {
"name": "4",
"y": 17494
}
}, {
"map": {
"name": "3",
"y": 2
}
}, {
"map": {
"name": "1",
"y": 1
}
}]
let revisedarray=input.reduce((acc,val)=>{
acc.push(val.map);
return acc;
},[])
console.log(revisedarray)
For more info about array reduce you can look at-mdn docs
Hi you can do this via pure js by looping through the array and extracting out the required output. Please check the code below.
var arr = [{ "map": { "name": "2", "y": 2 } }, { "map": { "name": "4", "y": 17494 } }, { "map": { "name": "3", "y": 2 } }, { "map": { "name": "1", "y": 1 } }];
var resultArr = arr.map(function(item) {
return item.map;
})
ES6 Short syntax, here A is original array of objects and A2 is output array of objects
let A2 = A.map(o=>o.map);
let jsonString = your_jsonString;
var blankArr = [];
let result = jsonString.map(item => item.map);
result.forEach(i => blankArr.push(i));
console.log(blankArr);

Filter an array of objects / convert array into another

could you please help me to convert data in format like :
"tanks": [
{
"id": "1",
"name": {
"id": 1,
"tor": "000"
},
"type": {
"id": 1,
"system": "CV-001"
}
}
]
into
"tanks":[
{
"type": 1,
"name": 1
}
]
As you can see, type.id in the first array is the same as just type in the second. It is like I have to iterate through the array(as I have not only one Object in it) and left only needed fields in Objects, but I am stuck.
Hope it is a little informative for you.
You can do this with a simple Array.map()
var obj = {
tanks : [
{
"id": "1",
"name": {
"id": 1,
"tor": "000"
},
"type": {
"id": 1,
"system": "CV-001"
}
},
{
"id": "2",
"name": {
"id": 2,
"tor": "200"
},
"type": {
"id": 2,
"system": "CV-002"
}
}
]
};
obj.tanks = obj.tanks.map(function(item) {
return {
name : item.name.id,
type : item.type.id
};
});
console.log(obj);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Categories

Resources