Related
I have an array of objects called posts with a nested field answer. I have different conditions depending on which I need to sort my array.
Example array
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "text",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "video",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "text",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "audio",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
What I need to do is...I want to sort all the answers with type "video" to start and after that type "audio" and then type "text" answers like so
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "video",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "text",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "audio",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "text",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
Any help would be appreciated. Thank you
You will need to loop through each entry in your posts array and sort the answers array inside each entry using a custom function.
The return value of the custom function (ele1, ele2) => {} should return a value > 0 if ele1 should be placed after ele2, a value < 0 if ele1 should be placed before ele2, and a value = 0 if they are considered equal.
const getRanking = (ele) => {
if (ele.type == "video") return 1;
if (ele.type == "audio") return 2;
if (ele.type == "text") return 3;
};
posts = posts.map(post => {
post.answers.sort((ele1, ele2) => {
return getRanking(ele1) - getRanking(ele2);
});
return post;
});
You should use lodash for this. Check out _.orderBy() method. Here is a helpful link: https://www.geeksforgeeks.org/lodash-_-orderby-method/
You need to add custom compare function.
This is the simplest solution for your question
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "text",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "video",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "text",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "audio",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
function type (t){
if(t==="video") return 1;
if(t==="audio") return 2;
if(t==="text")return 3;
}
function comparotor(a, b){
return type(a.type) - type(b.type)
}
posts.map(ele=>{
ele.answers.sort(comparotor);
})
console.log(posts);
You can easily achieve the result by using JS only by passing the comparator function to sort function
"video" => "v"
"audio" => "a"
"text" => "t"
You can use indexOf to check the first letter in a list of sorted letters(vat)
posts.map((o) =>o.answers.sort((a, b) => "vat".indexOf(a.type[0]) - "vat".indexOf(b.type[0])))
let posts = [
{
_id: "610b806ec6386ffa276b6d1c",
post: "CDat the difference between Equity and News channel?",
answers: [
{
_id: "613724604dd4b6f39b344b4c",
type: "text",
},
{
_id: "6113c826a64da80fe48ab543",
type: "video",
},
{
_id: "6113c740a64da80fe48ab534",
type: "audio",
},
{
_id: "611135cf7497d70b6cc2c5e0",
type: "video",
},
],
},
{
_id: "611e14329ff0c343540ae10e",
post: "How forex affects investment 6",
answers: [
{
_id: "61371b3a9bf14a39207fff8a",
type: "video",
},
{
_id: "613719369507fd12f93e3c62",
type: "text",
},
{
_id: "6135f28e29aeae3de45fc8c2",
type: "text",
},
{
_id: "6135f07c831da33c28fc1cf6",
type: "audio",
},
{
_id: "6135eb2d51a8830698d65cf3",
type: "text",
},
],
},
];
const result = posts.map((o) =>o.answers.sort((a, b) => "vat".indexOf(a.type[0]) - "vat".indexOf(b.type[0])));
console.log(result);
I have an array of json objects like below. Each object has permanent key 'type' and depending on the 'type', new keys are added.
So if type: 'text', we have a new key 'text'.
If type: 'notText', we have a new key 'attrs'.
arrayOfObj = [
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
}
]
Depending on the 'type' of each item i.e. if type: 'text', then I need to combine each 'text' into 1 object like so:
arrayOfObj = [
{
"type": "text",
"text": "= SO"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
}
]
I know that to start it I can use
if(this.arrayOfObj.map(ed=>ed.type) === 'text') {
Object.assign({}, ...arrayOfObj);
}
However it doesn't quite work and I'm unsure of how to go further.
Would anyone have any idea of how to accomplish this?
Example below.
const arrayOfObj = [ { type: "text", text: "=", }, { type: "text", text: " ", }, { type: "text", text: "S", }, { type: "text", text: "O", }, { type: "notText", attrs: { id: 20, data: "Something", }, }, ];
const output = arrayOfObj.reduce(
(a, b) => {
if (b.type === "text") {
a[0].text += b.text;
} else {
a.push({
type: b.type,
attrs: b.attrs,
});
}
return a;
},
[{ type: "text", text: "" }]
);
console.log(output);
You can use reduce method to do this.
arrayOfObj = [{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
},
{
"type": "notText",
"attrs": {
"id": 22,
"data": "Something",
}
}
]
const t = arrayOfObj.reduce((acc, curr) => {
if (curr.type === "text") {
const accTypeText = acc.find((v) => v.type === "text");
if (accTypeText) {
accTypeText.text += curr.text;
return [...acc];
}
}
return [...acc, curr];
}, [])
console.log(t);
Note: the map method return an array, so your if statement return always false
We can use Array.reduce to create the desired object from the arrayOfObj input, if it is of type 'text' concatenate, otherwise just set the attrs.
const arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } }, { "type": "someOtherType", "attrs": { "id": 35, "data": "Something else", } } ]
const result = Object.values(arrayOfObj.reduce((acc, { type, text, attrs }) => {
if (!acc[type]) acc[type] = { type };
if (type === 'text') acc[type].text = (acc[type].text || '') + text;
if (type !== 'text') acc[type].attrs = attrs;
return acc;
}, {}));
console.log('Result:', result)
I am breaking the problem step by step, I would do this:
let arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } } ]
let completeString = "";
arrayOfObj.forEach(x => x.type == "text" ? completeString += x.text : "")
arrayOfObj = arrayOfObj.filter(x => x.type == "notText");
arrayOfObj.push({ "type": "text", "text": completeString })
console.log(arrayOfObj);
This is how I would do it. A similar idea to #R3tep &#ikhvjs's answers using reduce, only much less elegant.
const arrayOfObj = [ { type: "text", text: "=", }, { type: "text", text: " ", }, { type: "text", text: "S", }, { type: "text", text: "O", }, { type: "notText", attrs: { id: 20, data: "Something", }, }, ];
function combineTexts(arrayOfObj) {
let noTextArray = arrayOfObj.filter(i => i.type !== 'text');
let allTexts = arrayOfObj.filter(i => i.type === 'text')
.map(i => i.text)
.reduce((a, b) => a + b, '');
noTextArray.unshift({ type: 'text', text: allTexts });
return noTextArray;
}
console.log(combineTexts(arrayOfObj))
I am trying to write a for or JQuery. Each loop so that It will generate a new JSON Object from an array in a desired format. I want to output a JSON Object from an input JavaScript Array. I have a following input array to convert:
INPUT:
[
{
"parent": "parent_1",
"child": "abc",
"data": "data1"
},
{
"parent": "parent_1",
"child": "def",
"data": "data2"
},
{
"parent": "parent_1",
"child": "ghi",
"data": "data3"
},
{
"parent": "parent_2",
"child": "jkl",
"data": "data4"
},
{
"parent": "parent_2",
"child": "acc",
"data": "data5"
},
{
"parent": "parent_3",
"child": "mjh",
"data": "data6"
},
{
"parent": "parent_3",
"child": "fg1",
"data": "data7"
},
{
"parent": "parent_2",
"child": "dfg",
"data": "data8"
},
{
"parent": "parent_3",
"child": "jkk",
"data": "data9"
},
{
"parent": "parent_4",
"child": "3ff",
"data": "data10"
},
{
"parent": "parent_3",
"child": "mhg",
"data": "data11"
},
{
"parent": "parent_1",
"child": "gnh",
"data": "data12"
}
]
so from above array want to run a for or JQuery. Each loop so that it will generate a new JSON Object in the following format:
OUTPUT:
[
{
"parent_1": {
"child": [
{
"name": "abc",
"data": "data1"
},
{
"name": "def",
"data": "data2"
},
{
"name": "gh1",
"data": "data3"
},
{
"name": "gnh",
"data": "data12"
}
]
}
},
{
"parent_2": {
"child": [
{
"name": "jkl",
"data": "data4"
},
{
"name": "acc",
"data": "data5"
},
{
"name": "dfg",
"data": "data8"
}
]
}
},
{
"parent_3": {
"child": [
{
"name": "mjh",
"data": "data6"
},
{
"name": "fg1",
"data": "data7"
},
{
"name": "jkk",
"data": "data9"
},
{
"name": "mhg",
"data": "data11"
}
]
}
},
{
"parent_4": {
"child": [
{
"name": "3ff",
"data": "data10"
}
]
}
}
]
You could group the data by using parent as key for an object and add the rest of the object to the children array of the group.
This approach does not muate the given data.
const
data = [{ parent: "parent_1", child: "abc", data: "data1" }, { parent: "parent_1", child: "def", data: "data2" }, { parent: "parent_1", child: "ghi", data: "data3" }, { parent: "parent_2", child: "jkl", data: "data4" }, { parent: "parent_2", child: "acc", data: "data5" }, { parent: "parent_3", child: "mjh", data: "data6" }, { parent: "parent_3", child: "fg1", data: "data7" }, { parent: "parent_2", child: "dfg", data: "data8" }, { parent: "parent_3", child: "jkk", data: "data9" }, { parent: "parent_4", child: "3ff", data: "data10" }, { parent: "parent_3", child: "mhg", data: "data11" }, { parent: "parent_1", child: "gnh", data: "data12" }],
result = Object.values(data.reduce((r, { parent, ...o }) => {
r[parent] ??= { [parent]: { children: [] } };
r[parent][parent].children.push(o);
return r;
}, []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think you want something like this
const convertArray = (arr, field) => {
const obj = {};
arr.forEach(elem => {
const param = elem[field];
if (!Array.isArray(obj[param])) obj[param] = [];
delete elem[field];
obj[param].push(elem);
});
return Object.keys(obj).map(elem => {
return { [elem]: { child: obj[elem] } };
});
}
then you would use as
convertArray(*array*, "parent")
You can use .reduce function, for example:
var array = [ {name: 'item 1', cate: 'cate-1'}, {name: 'item 2', cate: 'cate-2'} ]
var object = array.reduce(function(obj, item) {
if (!obj[item.cate]) obj[item.cate] = {child: []};
obj[item.cate].child.push(item);
return obj;
}, {})
console.log(object);
You can use the below code for this.
var arr = [{"parent":"parent_1","child":"abc","data":"data1"},{"parent":"parent_1","child":"def","data":"data2"},{"parent":"parent_1","child":"ghi","data":"data3"},{"parent":"parent_2","child":"jkl","data":"data4"},{"parent":"parent_2","child":"acc","data":"data5"},{"parent":"parent_3","child":"mjh","data":"data6"},{"parent":"parent_3","child":"fg1","data":"data7"},{"parent":"parent_2","child":"dfg","data":"data8"},{"parent":"parent_3","child":"jkk","data":"data9"},{"parent":"parent_4","child":"3ff","data":"data10"},{"parent":"parent_3","child":"mhg","data":"data11"},{"parent":"parent_1","child":"gnh","data":"data12"}];
var result = {};
$.each(arr, function (i, item) {
if(!result[item.parent]) {
result[item.parent] = [];
}
var data = {'child': {'name': item.child, 'data': item.data}};
(result[item.parent]).push(data);
});
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have a huge object, with almost 50k lines.
I need to add in each object new key with the current path of the node
Example:
let obj = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
And I need to change my object to return this:
obj = {
"path": "$",
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"path": "$.data.0",
"title": "Método:",
"data": [{
"path": "$.data.0.data.0",
"title": "Procedimento 1",
"data": [{
"path": "$.data.0.data.0.data.0",
"title": "CONTRASTE"
},
{
"path": "$.data.0.data.0.data.1",
"title": "CONTRASTE 2"
}
]
},
{
"path": "$.data.0.data.1",
"title": "Procedimento 2",
"data": [{
"path": "$.data.0.data.1.data.0",
"title": "CONTRASTE 3"
},
{
"path": "$.data.0.data.1.data.1",
"title": "CONTRASTE 4"
}
]
}
]
}]
}
If you notice, i added the key path inside each object for key data, with the current path of the node. This is what I need.
All my object are much bigger then this example, with much more nested objects
Performant version in case you have to deal with large files
const data = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
function PathUpdate(data, path) {
data.path = path;
const nd = data.data;
if (nd == null) return;
for (let i = 0; i < nd.length; i++) {
PathUpdate(nd[i], `${path}.data.${i}`);
}
}
console.log("before", { data });
PathUpdate(data, "$");
console.log("after", { data });
const data = {
title: "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
type: "template",
data: [
{
title: "Método:",
type: "top-level-component",
data: [
{
title: "Procedimento",
type: "navigation",
normal: "CONTRASTE",
checked: true,
data: [
{
type: "single-selection",
title: "CONTRASTE",
},
{
type: "single-selection",
title: "CONTRASTE 2",
},
],
},
{
title: "Procedimento 2",
type: "navigation",
normal: "CONTRASTE",
checked: false,
data: [
{
type: "single-selection",
title: "CONTRASTE 3",
},
{
type: "single-selection",
title: "CONTRASTE 4",
},
],
},
],
},
],
};
function addPathToObj(obj, path) {
obj.path = path;
for (const [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
value.forEach((item, index) => {
addPathToObj(item, `${path}.data.${index}`);
});
}
}
}
addPathToObj(data, "$");
console.log(data);
This is my JavaScript code:
<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
$("input#suggestZams").autocomplete({
source: "content/prevadzky/zam/zam_json2.php?letter=all",
minLength: 1,
delay: 0,
select: function(event, ui) {
alert(1);
}
});
});
//]]>
</script>
This is my HTML:
<input id="suggestZams" class="input" size="10" />
The URL zam_json2.php?letter=all returns this json:
[
{ "id": "31440", "value": "Andrej\u010d\u00e1k, Ing." },
{ "id": "31690", "value": "Alexovi\u010d , Ing." },
{ "id": "31796", "value": "Antoni\u010d , Ing." },
{ "id": "31989", "value": "Antolik , Ing." },
{ "id": "32010", "value": "Ambrozov\u00e1 RNDr., PhD." },
{ "id": "32014", "value": "Aksam\u00edt" },
{ "id": "32024", "value": "Angelovi\u010d" },
{ "id": "32102", "value": "Andrej\u010d\u00e1k" },
{ "id": "32168", "value": "Avukov\u00e1 , Ing." },
{ "id": "32177", "value": "Andr\u00e1\u0161" },
{ "id": "32181", "value": "Andrej\u010d\u00e1kov\u00e1 , Mgr." },
{ "id": "32403", "value": "Arend\u00e1\u0161 , Bc." },
{ "id": "47379", "value": "An\u010fal" },
{ "id": "47399", "value": "Adam\u00edk , Ing." },
{ "id": "50022", "value": "Abo\u0161i" },
{ "id": "50085", "value": "Armer\u00eda Olmedo , Ing." },
{ "id": "53468", "value": "Anto\u0161" },
{ "id": "54837", "value": "Adamec , Ing." },
{ "id": "56659", "value": "Apostolou" },
{ "id": "57820", "value": "Alez\u00e1r" },
{ "id": "58576", "value": "Andrej\u010d\u00e1k , Bc." },
{ "id": "58587", "value": "Aronov\u00e1 , Ing." },
{ "id": "58595", "value": "Abaffy , Bc." },
{ "id": "58607", "value": "Adamec , Bc." },
{ "id": "58643", "value": "Antu\u0161 , Ing." },
{ "id": "62277", "value": "Adam\u010d\u00e1k , Mgr." },
{ "id": "62379", "value": "Andruch" },
{ "id": "63415", "value": "Adamkovi\u010d , Ing." }
]
Quote:
Autocomplete can be customized to work
with various data sources, by just
specifying the source option. A data
source can be:
an Array with local data
a String, specifying a URL
a Callback
When a String is used, the
Autocomplete plugin expects that
string to point to a URL resource that
will return JSON data. It can be on
the same host or on a different one
(must provide JSONP). The request
parameter "term" gets added to that
URL. The data itself can be in the
same format as the local data
described above.
What you are doing looks odd to me. I think that you will actually need to edit the server side script so that it expects the query string variable term instead of letter and returns an array of strings or an array of {label, value} objects instead of {value, id}.
If the URL content/prevadzky/zam/zam_json2.php?letter=all is provides the "complete" list of words at once, you can do something along these lines:
$.getJSON("content/prevadzky/zam/zam_json2.php?letter=all", function(data) {
var datacopy = $.map(data, function(item) {
return {
label: item.value,
value: item.id
};
});
$("input#suggestZams").autocomplete({
source: datacopy,
minLength: 1,
delay: 0,
select: function(event, ui) {
alert(typeof ui);
}
});
});
If you want to get the data from a url you have to define a function for source:
source: function( request, response ) {
$.ajax({url: "content/prevadzky/zam/zam_json2.php?letter=all",
dataType: "json",
...
});
},
...
EDIT:
In the docs it says: source can be a URL. In this case, try to change the JSON response to have 'label' instead of 'id' in the returned objects.
Here an Script that work for me in jQuery 1.5.1.
source: function( request, response ) {
$.ajax({
url: "...",
dataType: "json",
...
success: function( data ) {
# data = json response
}
});
}