2016-04-06 31 views
6

Ho un array di oggetti nel seguente formato:condensazione l'oggetto matrice ricorsivamente in JavaScript

{ 
    "country": "India", 
    "children": [ 
    { 
     "name": "Karnataka", 
     "type": "State", 
     "children": [ 
     { 
      "name": "", 
      "type": "city" 
     }, 
     { 
      "name": "Bangalore", 
      "type": "city" 
     }, 
     { 
      "name": "Mangalore", 
      "type": "city" 
     } 
     ] 
    }, 
    { 
     "name": "Kerala", 
     "type": "State", 
     "children": [ 
     { 
      "name": "", 
      "type": "city" 
     } 
     ] 
    }, 
    { 
     "name": "Maharashtra", 
     "type": "State", 
     "children": [ 
     { 
      "name": "Mumbai", 
      "type": "city" 
     }, 
     { 
      "name": "Pune", 
      "type": "city" 
     } 
     ] 
    } 
    ] 
} 

Ogni oggetto ha un elemento di bambini che contiene i dettagli dell'elemento. Ho bisogno di ripetere iteramente in modo ricorsivo l'oggettojson e rimuovere tutti i nodi la cui stringa name è vuota fino alla radice. Per il formato JSON sopra, l'uscita dovrebbe essere come di seguito:

{ 
    "country": "India", 
    "children": [ 
    { 
     "name": "Karnataka", 
     "type": "State", 
     "children": [ 
     { 
      "name": "Bangalore", 
      "type": "city" 
     }, 
     { 
      "name": "Mangalore", 
      "type": "city" 
     } 
     ] 
    }, 
    { 
     "name": "Kerala", 
     "type": "State", 
     "children": [ 
     ] 
    }, 
    { 
     "name": "Maharastra", 
     "type": "State", 
     "children": [ 
     { 
      "name": "Mumbai", 
      "type": "city" 
     }, 
     { 
      "name": "Pune", 
      "type": "city" 
     } 
     ] 
    } 
    ] 
} 

come farlo in javascript in modo ricorsivo utilizzando Underscorejs.

+0

'Mappa matrice # ..? – Rayon

+0

@ RayonDabre-mi sembra * reduceRight * ed elimina i membri indesiderati è meglio, ma underscore.js ha questo? Se no, ce n'è uno integrato. – RobG

+0

[Questa domanda SO] (http://stackoverflow.com/questions/36171667/find-and-remove-empty-properties-from-objects/36171824) potrebbe aiutarti – Aides

risposta

3

Questo è un ricorsiva soluzione con Array#filter().

function filterName(a) { 
 
    if (a.name) { 
 
     if (Array.isArray(a.children)) { 
 
      a.children = a.children.filter(filterName); 
 
     } 
 
     return true; 
 
    } 
 
} 
 

 
var object = { "country": "India", "children": [{ "name": "Karnataka", "type": "State", "children": [{ "name": "", "type": "city" }, { "name": "Bangalore", "type": "city" }, { "name": "Mangalore", "type": "city" }] }, { "name": "Kerala", "type": "State", "children": [{ "name": "", "type": "city" }] }, { "name": "Maharashtra", "type": "State", "children": [{ "name": "Mumbai", "type": "city" }, { "name": "Pune", "type": "city" }] }] }; 
 

 
object.children.forEach(filterName); 
 
document.write("<pre>" + JSON.stringify(object, 0, 4) + "</pre>");

1

Prova questo:

function condense(arr) { 

    arr.children = arr.children.map(function(c) { 
    c.children = c.children.filter(function(c1) { 
     return c1.name; 
    }); 
    return c; 
    }); 

    return arr; 
} 

ho scorrere i bambini (con map), poi filtrare la matrice per bambini con filter. Saranno mantenuti solo i bambini con un nome non nullo o vuoto.

Ecco uno jsfiddle.

+0

Ho provato un approccio simile. Volevo provare questo con la ricorsione. – zilcuanu

+0

Perché? Hai solo due livelli di profondità. Inoltre, al primo livello, tieni i bambini vuoti, sul secondo li cancelli. Non sembra un buon candidato alla ricorsione. – Derlin

1

Non au fait con underscore.js. È possibile farlo con ES5 reduceRight ed eliminare i membri che non si desidera, dovrebbe essere più efficiente di altri approcci. Di seguito utilizza la ricorsione (che non è così efficace come l'elaborazione seriale, ma è probabile che meno codice), in modo da poter nido gli oggetti profondo come si amano:

function removeEmpty(obj) { 
 
    obj.children.reduceRight(function (acc, child, i) { 
 
    if (!child.name) { 
 
     obj.children.splice(i, 1); 
 
    } else if (child.children) { 
 
     removeEmpty(child); 
 
    } 
 
    return null; 
 
    }, null); 
 
    return obj; 
 
} 
 

 
// Test 
 
var data = { 
 
    "country": "India", 
 
    "children": [ 
 
    { 
 
     "name": "Karnataka", 
 
     "type": "State", 
 
     "children": [ 
 
     { 
 
      "name": "", 
 
      "type": "city" 
 
     }, 
 
     { 
 
      "name": "Bangalore", 
 
      "type": "city" 
 
     }, 
 
     { 
 
      "name": "Mangalore", 
 
      "type": "city" 
 
     } 
 
     ] 
 
    }, 
 
    { 
 
     "name": "Kerala", 
 
     "type": "State", 
 
     "children": [ 
 
     { 
 
      "name": "", 
 
      "type": "city" 
 
     } 
 
     ] 
 
    }, 
 
    { 
 
     "name": "Maharashtra", 
 
     "type": "State", 
 
     "children": [ 
 
     { 
 
      "name": "Mumbai", 
 
      "type": "city" 
 
     }, 
 
     { 
 
      "name": "Pune", 
 
      "type": "city" 
 
     } 
 
     ] 
 
    } 
 
    ] 
 
} 
 

 

 
document.write('Original:<br>' + JSON.stringify(data) + '<br><br>' + 
 
       'Modified:<br>' + JSON.stringify(removeEmpty(data)));

+0

Oh, l'uso di 'reduceRight' è così confuso qui, dato che non stai riducendo nulla ... – Bergi

+0

Sì, è solo per iterare dalla lunghezza a 0, l'accumulatore viene ignorato. Forse dovrebbe esserci un * forEachRight *? ;-) Pensandoci ora, * return null * può essere omesso. – RobG

+0

Forse anche '_' invece di' acc' – Bergi

1

Questo è molto specifico per il vostro esempio.

Link to fiddle

var obj = { 
 
    "country": "India", 
 
    "children": [{ 
 
    "name": "Karnataka", 
 
    "type": "State", 
 
    "children": [{ 
 
     "name": "", 
 
     "type": "city" 
 
    }, { 
 
     "name": "Bangalore", 
 
     "type": "city" 
 
    }, { 
 
     "name": "Mangalore", 
 
     "type": "city" 
 
    }] 
 
    }, { 
 
    "name": "Kerala", 
 
    "type": "State", 
 
    "children": [{ 
 
     "name": "", 
 
     "type": "city" 
 
    }] 
 
    }, { 
 
    "name": "Maharashtra", 
 
    "type": "State", 
 
    "children": [{ 
 
     "name": "Mumbai", 
 
     "type": "city" 
 
    }, { 
 
     "name": "Pune", 
 
     "type": "city" 
 
    }] 
 
    }] 
 
}; 
 

 
//Before 
 
document.write("BEFORE: "+JSON.stringify(obj)); 
 
//After 
 
document.write("AFTER: "+JSON.stringify(checkJSON(obj))); 
 

 
function checkJSON(obj) { 
 
    $.each(obj.children, function(index, value) { 
 
    if ($.isArray(value.children)) { 
 
     $.each(value.children, function(index, value) { 
 
     if (value.name == '') { 
 
      delete value.name; 
 
     } 
 
     }); 
 
    } 
 
    }); 
 
    return obj; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

1
non

Probabilmente la via più breve, ma funziona:

obj.children = _.each(obj.children, filter); 

function filter(child, index, arr) { 
    if (child && child.name === '') { 
    // remove the ones without name 
    arr.splice(index, 1); 

    } else if (_.has(child, 'children')) { 
    // remove nested children 
    child.children = _.each(child.children, filter); 

    // check for empty children array and remove it (if needed) 
    /* 
    if (child.children.length === 0) { 
     delete child['children']; 
    } 
    */ 
    } 

    return child; 
} 

Fiddle: https://jsfiddle.net/gnmosu5p/2/

1

Conosco un un ricorsiva si chiede pproach ma non posso evitare di dare un singolo liner qui.

var newData = JSON.parse(JSON.stringify(data).replace(/{"name":"".+?},?/g, "")); 

dove data è l'oggetto inizialmente proposta da ristrutturare.

È un po 'più lento delle funzioni di matrice, ma un vantaggio di questo metodo è preservare l'oggetto dati originale così com'è, mentre tutti i metodi dell'array sovrascriveranno l'oggetto dati originale a meno che non lo si cloni.