I'm working on this script that takes this as input:
{
"success":true,
"entities":[
{
"pais":{
"id":2,
"nombre":"Bolivia"
}
},
{
"pais":{
"id":5,
"nombre":"Colombia"
}
},
{
"pais":{
"id":6,
"nombre":"Costa Rica"
}
}
],
"idToUpdate":"1"
}
And outputs this: Bolivia, Colombia, Costa Rica. Taking the input example I provide earlier this is how I call the function:
showList('#distTd-' + data.idToUpdate, paisesFromEntity, data.entities);
That's fine but I now I'm getting this input also:
{
"success":true,
"entities":{
"id":5,
"nombre":"dgdfgdfg",
"direccion":"5654645",
"telefono":"656546",
"pais":[
{
"id":1,
"nombre":"Argentina"
},
{
"id":2,
"nombre":"Bolivia"
}
]
}
}
Which differs a bit from the first input so script on this case is not working because the pais key is missing. Can any help me to get ride of this? I can't change the server side that returns the new JSON.
var fullList = [];
$(document).ready(function(){
var uniq = function (arr) {
var ids = {};
arr.forEach(function(obj) {
objPais = obj.pais.id === "undefined" ? obj.id : obj.pais.id;
ids[objPais] = obj;
});
return Object.keys(ids).map(function(id) {
return ids[id];
});
};
function showList(selector) {
var items = [].slice.call(arguments, 1).filter(function(item) { return item; }),
arr = fullList.concat.apply(fullList, items),
list = uniq(arr),
spans = list.map(function(val, i) {
return '<span id="' + val.pais.id +'">' + val.pais.nombre + '</span>';
});
if ($(selector).text().length >0) {
$(selector).append(', ');
}
$(selector).append(spans.join(', '));
}
$("#btn1").on("click", function(){
var arr1 = [{"pais":{"id":1,"nombre":"Country1"}},{"pais":{"id":2,"nombre":"Country2"}}],
arr2 = [{"pais":{"id":1,"nombre":"Country1"}},{"pais":{"id":3,"nombre":"Country3"}},{"pais":{"id":4,"nombre":"Country4"}}],
arr3 =[{"pais":[{"id":1,"nombre":"Argentina"},{"id":2,"nombre":"Bolivia"}]}];
showList('#update', arr1, undefined, arr2, arr3);
});
$("#btn2").on("click", function(){
var arr3 = [{"pais":{"id":5,"nombre":"Country5"}},{"pais":{"id":6,"nombre":"Country6"}}],
arr4 = [{"pais":{"id":7,"nombre":"Country7"}},{"pais":{"id":8,"nombre":"Country8"}}];
showList('#update', arr3, arr4);
});
});
Here is a jsBin working code
Transform second format to first format:
arr3copy = [];
for (var i = 0; i < arr3[0].pais.length; i++) {
arr3copy.push({"pais":{"id":arr3[0].pais[i].id,"nombre":arr3[0].pais[i].nombre}});
};
arr3 = arr3copy;
Related
I have one plain string including some conditions like this.
const optionString = '{2109} AND ({2370} OR {1701} OR {2702}) AND {1234} AND ({2245} OR {2339})';
I need to get object like the following structure from above.
const output = {
and: [
2109,
{ or: [2370, 1071, 2702] },
1234,
{ or: [2245, 2339] },
];
Currently, I have tried to do like following
function parseFormat(strArg) {
var
category,
output = [], // Output
str = strArg.trim(); // Remove unwanted space before processing
str.split('AND').forEach(function(line) {
var removedString = line.replace(/[\])}[{(]/g, '');
var item = removedString.split('OR');
item = item.map(it => {
return Number(it.replace(/ /g, ''))
})
if(item.length > 0) {
output.push(item)
} else {
output.push(item[0])
}
});
return output;
}
And its output is like here.
[
[
1069
],
[
1070,
1071,
1072
],
[
1244
],
[
1245,
1339
]
]
I have one question first
How to add key AND and OR in the current result?
If you know a good solution on the performance side, please update me.
Thanks for taking the time.
const optionString = '{2109} AND ({2370} OR {1701} OR {2702}) AND {1234} AND ({2245} OR {2339})';
const parseExpr = s => {
let op, m, a = [];
while(s?.length) {
if(m = /^{(?<num>[0-9]+)}( (?<rest>.*))?/.exec(s)) {
a.push(+m.groups.num);
s = m.groups.rest;
}
else if(m = /^(?<op>[A-Z]+)( (?<rest>.*))?/.exec(s)) {
let t = m.groups.op.toLowerCase();
if(op && op!==t) throw new Error('Multiple operators cannot exist at same level in syntax tree')
else op = t;
s = m.groups.rest;
}
else if(s.startsWith('(')) {
for(let i=0, level=0; i<s.length; i++) {
if(s.charAt(i)==='(') level++;
if(s.charAt(i)===')') level--;
if(!level) {
a.push(parseExpr(s.substring(1, i)));
s = s.substring(i+2);
break;
}
if(i===s.length-1) throw new Error('Mismatched brackets')
}
}
else throw new Error(`Unparseable expression: ${s}`);
}
return { [op]: a };
}
const result = parseExpr(optionString)
console.log(result)
I have this chunk of code and I want to print this out.
a
|->b
|->c
|->e
It works when I use
let spaceStr = " ".repeat(level) + "|->";
but not when I use the helper function getSpace.
It only prints the following:
a
|->b
I cannot figure out why. Can someone explain to me?
const obj =
{ name: 'a', children:
[ { name: 'b', children: [] }
, { name: 'c', children:
[ { name: 'e', children: [] }
]
}
]
}
function getSpace(level){
var str = '';
for (i=0; i < level; i++){
str += ' ';
}
str += '|->';
return str
}
function getPath(obj, level) {
let result = [];
let resultString = '';
let spaceStr = " ".repeat(level) + "|->";
// let spaceStr = getSpace(level);
if (obj.children.length === 0) {
return spaceStr+obj.name;
} else {
if (level === 0) {
result.push(obj.name);
} else {
result.push(spaceStr + obj.name);
}
for (i=0;i<obj.children.length;i++){
result.push(getPath(obj.children[i], level+1));
}
}
return result;
}
function printPath(result){
for (i=0;i<result.length;i++){
console.log(result[i]);
}
return
}
printPath(getPath(obj,0).flat());
By using i=0 in your loops, you're not scoping the variable i correctly to the loop. Instead, it will bubble up to the closest instance of that variable name (until it hits the global scope). Consider using let i = 0 in your loops to properly scope the variable. See the following functioning code:
const obj = {
"name": "a",
"children": [{
"name": "b",
"children": []
},
{
"name": "c",
"children": [{
"name": "e",
"children": []
}]
}
]
}
function getSpace(level){
var str = '';
for (let i = 0; i < level; i++){
str += ' ';
}
str += '|->';
return str
}
function getPath(obj, level) {
let result = [];
let resultString = '';
//let spaceStr = " ".repeat(level) + "|->";
let spaceStr = getSpace(level);
if (obj.children.length === 0) {
return spaceStr+obj.name;
} else {
if (level === 0) {
result.push(obj.name);
} else {
result.push(spaceStr + obj.name);
}
for (let i = 0;i<obj.children.length;i++){
result.push(getPath(obj.children[i], level+1));
}
}
return result;
}
function printPath(result){
for (let i = 0;i<result.length;i++){
console.log(result[i]);
}
return
}
printPath(getPath(obj,0).flat());
how could i make this function recursive and remove the for in loop here.
where i get the result of Maark, Maary etc by using this function.
function get_suggestion_array_from_object () {
var test_searchstring = 'Ma';
var test_current_object_string = '{"a":{"r":{"k":0,"y":0}, "s":{"s":0,"y":0}}}';
var test_current_object = JSON.parse(test_current_object_string);
var suggestion_array = [];
for (var item in test_current_object) {
var one = item;
for( var item2 in test_current_object[item]) {
var two = item2;
console.log( test_searchstring + one + two );
}
}
}
}
get_suggestion_array_from_object ()
function traverse(path, string = ""){
const result = [];
for(const [key, value] of Object.entries(path)){
if(typeof value === "object"){
result.push(...traverse(value, string + key));
} else {
result.push(string + key);
}
}
return result;
}
So one can do:
const result = traverse({a: { r: {k: 0, y: 0}}}, "M");
I'm trying to search through a list of multiple values.
Here is the an example of the values:
[
{
"color":"blue",
"medium":"Sculpture",
"place":"Garage"
}
{
"color":"red",
"medium":"Painting",
"place":"Pool"
}
]
Below is my code. Works great to find a single value. But I need to find multiple values. For example I need to look and find the results for queries such as: "red blue" or "blue Painting".
It should return results that have both word.
I don't really know how to solve this, does anybody have an idea?
Thanks a lot
function search(){
var search = $('#search').val();
if(search.length < 1) {
return null;
};
var searches = search.split(" ");
var fields = ["color","medium","place"];
var results = [];
$.each(searches, function(i, word){
var wordResult = searchInJson(word,fields,json);
if( wordResult.length > 0 ) {
results.push(wordResult);
}
});
var results = searchInJson(searches,fields,json);
displaySearchResults(results);
};
function searchInJson(search,fields,json) {
var regex = new RegExp(search);
var results = [];
$.each(json, function(i, image){
$.each(fields, function(j, fieldname){
var field = image[fieldname];
if (regex.test(field)) {
results.push( image );
}
});
});
return results;
}
Here's a quick method to try:
var list = [
{
"color":"blue",
"medium":"Sculpture",
"place":"Garage"
},
{
"color":"red",
"medium":"Painting",
"place":"Pool"
}
];
var search = "red painting";
var results = list.filter(function (el) {
var s = search.toLowerCase().split(" ");
for (var key in el) {
for (var i=0; i < s.length; i++) {
if (el[key].toLowerCase() == s[i]) { // this could use indexOf depending on if you want to match partial words
s.splice(i,1);
i--;
if (!s.length) return true;
}
}
}
return false;
});
console.log(results);
I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}