फास्टन / अन-फ्लैटन को नेस्टेड JSON ऑब्जेक्ट्स का सबसे तेज़ तरीका


159

मैंने कुछ कोड को समतल और संयुक्त-समतल जटिल / नेस्टेड JSON ऑब्जेक्ट्स में फेंक दिया। यह काम करता है, लेकिन यह थोड़ा धीमा है ('लंबी स्क्रिप्ट' चेतावनी को ट्रिगर करता है)।

चपटे नामों के लिए मुझे चाहिए "।" परिसीमन और सरणियों के लिए [INDEX] के रूप में।

उदाहरण:

un-flattened | flattened
---------------------------
{foo:{bar:false}} => {"foo.bar":false}
{a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"}
[1,[2,[3,4],5],6] => {"[0]":1,"[1].[0]":2,"[1].[1].[0]":3,"[1].[1].[1]":4,"[1].[2]":5,"[2]":6}

मैंने एक बेंचमार्क बनाया कि ~ मेरे उपयोग के मामले का अनुकरण करता है http://jsfiddle.net/WSzec/

  • एक नेस्टेड JSON ऑब्जेक्ट प्राप्त करें
  • इसे समतल करें
  • इसके माध्यम से देखें और चपटा होने पर संभवतः इसे संशोधित करें
  • अनफ्लैट करें इसे वापस मूल नेस्टेड स्वरूप में भेज दिया जाना चाहिए

मैं तेज़ कोड पसंद करूँगा: स्पष्टीकरण के लिए, कोड जो JSFiddle बेंचमार्क ( http://jsfiddle.net/WSzec/ ) को पूर्ण करता है , IE 9+, FF 24+ और Chrome 29 में काफी तेज़ (~ 20% + अच्छा होगा) +।

यहां प्रासंगिक जावास्क्रिप्ट कोड है: करंट फास्टेस्ट: http://jsfiddle.net/WSzec/6/

JSON.unflatten = function(data) {
    "use strict";
    if (Object(data) !== data || Array.isArray(data))
        return data;
    var result = {}, cur, prop, idx, last, temp;
    for(var p in data) {
        cur = result, prop = "", last = 0;
        do {
            idx = p.indexOf(".", last);
            temp = p.substring(last, idx !== -1 ? idx : undefined);
            cur = cur[prop] || (cur[prop] = (!isNaN(parseInt(temp)) ? [] : {}));
            prop = temp;
            last = idx + 1;
        } while(idx >= 0);
        cur[prop] = data[p];
    }
    return result[""];
}
JSON.flatten = function(data) {
    var result = {};
    function recurse (cur, prop) {
        if (Object(cur) !== cur) {
            result[prop] = cur;
        } else if (Array.isArray(cur)) {
             for(var i=0, l=cur.length; i<l; i++)
                 recurse(cur[i], prop ? prop+"."+i : ""+i);
            if (l == 0)
                result[prop] = [];
        } else {
            var isEmpty = true;
            for (var p in cur) {
                isEmpty = false;
                recurse(cur[p], prop ? prop+"."+p : p);
            }
            if (isEmpty)
                result[prop] = {};
        }
    }
    recurse(data, "");
    return result;
}

EDIT 1 ने @Bergi के कार्यान्वयन के लिए उपरोक्त संशोधन किया जो वर्तमान में सबसे तेज है। एक तरफ के रूप में, "regex.exec" के बजाय ".indexOf" का उपयोग करना FF में लगभग 20% तेज है लेकिन क्रोम में 20% धीमा है; तो मैं regex के साथ रहना आसान हूँ क्योंकि यह सरल है (यहाँ indexOf का उपयोग करने का मेरा प्रयास regex http://jsfiddle.net/WSzec/2/ ) को बदलने के लिए है ।

EDIT 2 बिल्डिंग @Bergi के विचार पर मैं एक तेज गैर-रेगेक्स संस्करण (FF में 3x और क्रोम में 10% तेज) बनाने में कामयाब रहा। http://jsfiddle.net/WSzec/6/ इसमें (वर्तमान में) प्रमुख नामों के नियमों को लागू करने के लिए बस, चाबियाँ एक पूर्णांक के साथ शुरू नहीं हो सकती हैं या एक अवधि शामिल कर सकते हैं।

उदाहरण:

  • {"foo": {"bar": [0]}} => {"foo.bar.0": 0}

EDIT 3 @AaditMShah के इनलाइन पथ पार्सिंग दृष्टिकोण (String.split के बजाय) को जोड़ने से अनफ़्लैट प्रदर्शन को बेहतर बनाने में मदद मिली। समग्र प्रदर्शन में सुधार के साथ मैं बहुत खुश हूं।

नवीनतम jsfiddle और jsperf:

http://jsfiddle.net/WSzec/14/

http://jsperf.com/flatten-un-flatten/4


7
"JSON ऑब्जेक्ट" जैसी कोई चीज नहीं है । जेएस वस्तुओं के बारे में सवाल लगता है।
फेलिक्स क्लिंग सेप

1
यह प्रश्न कोड समीक्षा StackExchange साइट के लिए अधिक उपयुक्त प्रतीत होता है: codereview.stackexchange.com
Aadit M Shah

6
@FelixKling - JSON ऑब्जेक्ट से मेरा मतलब जेएस ऑब्जेक्ट से है जिसमें केवल आदिम जावास्क्रिप्ट प्रकार होते हैं। उदाहरण के लिए, आप जेएस ऑब्जेक्ट में एक फ़ंक्शन डाल सकते हैं, लेकिन इसे JSON में अनुक्रमित नहीं किया जाएगा - यानी JSON.stringify ({fn: function () {अलर्ट ('a';}}); -
लुईस रिक्की

2
[1].[1].[0]मुझे गलत लगता है। क्या आप सुनिश्चित हैं कि यह वांछित परिणाम है?
बर्गी

2
दुर्भाग्य से एक बग है: दिनांक ऑब्जेक्ट एक खाली JSON में कनवर्ट किए जाते हैं।
जियासकेओ

जवाबों:


217

यहाँ मेरा बहुत छोटा कार्यान्वयन है:

Object.unflatten = function(data) {
    "use strict";
    if (Object(data) !== data || Array.isArray(data))
        return data;
    var regex = /\.?([^.\[\]]+)|\[(\d+)\]/g,
        resultholder = {};
    for (var p in data) {
        var cur = resultholder,
            prop = "",
            m;
        while (m = regex.exec(p)) {
            cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
            prop = m[2] || m[1];
        }
        cur[prop] = data[p];
    }
    return resultholder[""] || resultholder;
};

flattenज्यादा नहीं बदला है (और मुझे यकीन नहीं है कि आपको वास्तव में उन isEmptyमामलों की आवश्यकता है ):

Object.flatten = function(data) {
    var result = {};
    function recurse (cur, prop) {
        if (Object(cur) !== cur) {
            result[prop] = cur;
        } else if (Array.isArray(cur)) {
             for(var i=0, l=cur.length; i<l; i++)
                 recurse(cur[i], prop + "[" + i + "]");
            if (l == 0)
                result[prop] = [];
        } else {
            var isEmpty = true;
            for (var p in cur) {
                isEmpty = false;
                recurse(cur[p], prop ? prop+"."+p : p);
            }
            if (isEmpty && prop)
                result[prop] = {};
        }
    }
    recurse(data, "");
    return result;
}

एक साथ, वे आपके बेंचमार्क को लगभग आधे समय में चलाते हैं (ओपेरा 12.16: ~ 900ms के बजाय ~ 1900ms, Chrome 29: ~ 800ms के बजाय ~ 1600ms)।

नोट: यह और अधिकांश अन्य समाधानों का उत्तर दिया गया है कि यहां गति पर ध्यान केंद्रित किया गया है और प्रोटोटाइप प्रदूषण के लिए अतिसंवेदनशील हैं और अविश्वसनीय वस्तुओं पर इस्तेमाल नहीं किया जाना चाहिए।


1
यह भी खूब रही! रेगेक्स उल्लेखनीय रूप से अच्छी तरह से चलता है (विशेष रूप से क्रोम में), मैंने इसे इंडेक्सऑफ तर्क के साथ बदलने की कोशिश की, लेकिन केवल एफएफ में गति का एहसास करने में सक्षम था। मैं इस प्रश्न के लिए एक भरपूर इजाफा कर रहा हूं कि यह देखने के लिए कि क्या एक और चतुर सुधार से हड़कंप मच सकता है, लेकिन अभी तक यह उस चीज से अधिक है जिसकी मैं उम्मीद कर रहा था।
लुईस रिक्की

1
मैं string.split () के साथ regex.exec () की जगह और कुंजी प्रारूप को सरल करके आपके कार्यान्वयन से अधिक गति को पीसने में कामयाब रहा। मैं आपको कुछ दिनों पहले पुरस्कार देता हूँ, लेकिन मुझे लगता है कि 'सार्थक अनुकूलन की दीवार' पहुँच चुकी है।
लुईस रिक्की

JSON.flatten ({}); // {'': {}} - आप var result = {} के बाद एक पंक्ति जोड़ सकते हैं; - अगर (परिणाम === डेटा) रिटर्न डेटा;
इवान

@ इवान: आह, उस किनारे के मामले के लिए धन्यवाद, हालांकि शब्दार्थ यह वास्तव में खाली वस्तुओं के लिए एक अतिरिक्त प्रतिनिधित्व की आवश्यकता होगी। लेकिन नहीं, result === dataकाम नहीं करेंगे, वे कभी भी समान नहीं हैं।
बेर्गी

@Bergi हाँ तुम सही हो। Object.keys (डेटा) .length === 0 हालांकि काम करता है
इवान

26

मैंने JSON ऑब्जेक्ट को दो फ़ंक्शन लिखे flattenऔर दिए unflatten


एक JSON ऑब्जेक्ट समतल करें :

var flatten = (function (isArray, wrapped) {
    return function (table) {
        return reduce("", {}, table);
    };

    function reduce(path, accumulator, table) {
        if (isArray(table)) {
            var length = table.length;

            if (length) {
                var index = 0;

                while (index < length) {
                    var property = path + "[" + index + "]", item = table[index++];
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else accumulator[path] = table;
        } else {
            var empty = true;

            if (path) {
                for (var property in table) {
                    var item = table[property], property = path + "." + property, empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else {
                for (var property in table) {
                    var item = table[property], empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            }

            if (empty) accumulator[path] = table;
        }

        return accumulator;
    }
}(Array.isArray, Object));

प्रदर्शन :

  1. यह ओपेरा में मौजूदा समाधान से तेज है। वर्तमान समाधान ओपेरा में 26% धीमा है।
  2. यह फ़ायरफ़ॉक्स में वर्तमान समाधान की तुलना में तेज़ है। वर्तमान समाधान फ़ायरफ़ॉक्स में 9% धीमा है।
  3. यह क्रोम में वर्तमान समाधान से तेज है। क्रोम में वर्तमान समाधान 29% धीमा है।

एक JSON वस्तु को अनफ्लैट करें :

function unflatten(table) {
    var result = {};

    for (var path in table) {
        var cursor = result, length = path.length, property = "", index = 0;

        while (index < length) {
            var char = path.charAt(index);

            if (char === "[") {
                var start = index + 1,
                    end = path.indexOf("]", start),
                    cursor = cursor[property] = cursor[property] || [],
                    property = path.slice(start, end),
                    index = end + 1;
            } else {
                var cursor = cursor[property] = cursor[property] || {},
                    start = char === "." ? index + 1 : index,
                    bracket = path.indexOf("[", start),
                    dot = path.indexOf(".", start);

                if (bracket < 0 && dot < 0) var end = index = length;
                else if (bracket < 0) var end = index = dot;
                else if (dot < 0) var end = index = bracket;
                else var end = index = bracket < dot ? bracket : dot;

                var property = path.slice(start, end);
            }
        }

        cursor[property] = table[path];
    }

    return result[""];
}

प्रदर्शन :

  1. यह ओपेरा में मौजूदा समाधान से तेज है। वर्तमान समाधान ओपेरा में 5% धीमा है।
  2. यह फ़ायरफ़ॉक्स में वर्तमान समाधान की तुलना में धीमी है। मेरा समाधान फ़ायरफ़ॉक्स में 26% धीमा है।
  3. यह क्रोम में वर्तमान समाधान की तुलना में धीमा है। मेरा समाधान क्रोम में 6% धीमा है।

एक JSON ऑब्जेक्ट को समतल और उन्मुक्त करें :

कुल मिलाकर मेरा समाधान या तो समान रूप से अच्छा प्रदर्शन करता है या वर्तमान समाधान से भी बेहतर है।

प्रदर्शन :

  1. यह ओपेरा में मौजूदा समाधान से तेज है। वर्तमान समाधान ओपेरा में 21% धीमा है।
  2. यह फ़ायरफ़ॉक्स में वर्तमान समाधान जितना तेज़ है।
  3. यह फ़ायरफ़ॉक्स में वर्तमान समाधान की तुलना में तेज़ है। वर्तमान समाधान क्रोम में 20% धीमा है।

आउटपुट स्वरूप :

एक चपटा वस्तु वस्तु गुणों के लिए डॉट संकेतन और सरणी सूचकांकों के लिए ब्रैकेट अंकन का उपयोग करता है:

  1. {foo:{bar:false}} => {"foo.bar":false}
  2. {a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"}
  3. [1,[2,[3,4],5],6] => {"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}

मेरी राय में यह प्रारूप केवल डॉट नोटेशन का उपयोग करने से बेहतर है:

  1. {foo:{bar:false}} => {"foo.bar":false}
  2. {a:[{b:["c","d"]}]} => {"a.0.b.0":"c","a.0.b.1":"d"}
  3. [1,[2,[3,4],5],6] => {"0":1,"1.0":2,"1.1.0":3,"1.1.1":4,"1.2":5,"2":6}

लाभ :

  1. किसी ऑब्जेक्ट को समतल करना वर्तमान समाधान की तुलना में तेज़ है।
  2. किसी वस्तु को समतल करना और अप्रभावित करना वर्तमान समाधान की तुलना में तेज या तेज है।
  3. चपटी वस्तुएं पठनीयता के लिए डॉट नोटेशन और ब्रैकेट नोटेशन दोनों का उपयोग करती हैं।

नुकसान :

  1. किसी ऑब्जेक्ट को अनफ़्लैट करना अधिकांश (लेकिन सभी नहीं) मामलों में वर्तमान समाधान की तुलना में धीमा है।

वर्तमान JSField डेमो ने आउटपुट के रूप में निम्नलिखित मान दिए:

Nested : 132175 : 63
Flattened : 132175 : 564
Nested : 132175 : 54
Flattened : 132175 : 508

मेरे अद्यतन JSField डेमो ने आउटपुट के रूप में निम्नलिखित मान दिए:

Nested : 132175 : 59
Flattened : 132175 : 514
Nested : 132175 : 60
Flattened : 132175 : 451

मुझे वास्तव में यकीन नहीं है कि इसका क्या मतलब है, इसलिए मैं jsPerf परिणामों के साथ रहना चाहूंगा। सभी jsPerf के बाद एक प्रदर्शन बेंचमार्किंग उपयोगिता है। JSFiddle नहीं है।


बहुत ही शांत। मैं वास्तव में समतल करने के लिए शैली पसंद करता हूं, Array.isArray और ऑब्जेक्ट को एक करीबी दायरे में लाने के लिए अनाम कार्यों का उपयोग करता हूं। मुझे लगता है कि JSPerf परीक्षण के लिए आपके द्वारा उपयोग की जाने वाली परीक्षण वस्तु हालांकि बहुत सरल है। मैंने डेटा के एक बड़े जटिल नेस्टेड टुकड़े के वास्तविक मामले का अनुकरण करने के लिए अपने jsfiddle बेंचमार्क में ऑब्जेक्ट "fillObj ({}, 4)" बनाया।
लुई रिक्की

मुझे अपनी वस्तु के लिए कोड दिखाएं और मैं इसे बेंचमार्क में शामिल करूंगा।
आदित एम शाह

2
@LastCoder हम्म, आपका वर्तमान कार्यान्वयन अधिकांश ब्राउज़रों (विशेष रूप से फ़ायरफ़ॉक्स) में मेरा की तुलना में तेज़ लगता है। दिलचस्प है कि ओपेरा में मेरा कार्यान्वयन तेज है और यह क्रोम में भी इतना बुरा नहीं है। मुझे नहीं लगता कि एल्गोरिथ्म की गति निर्धारित करने के लिए इतना बड़ा डेटा सेट एक आदर्श कारक है क्योंकि: 1) बड़े डेटा सेट में बड़ी मात्रा में मेमोरी, पेज स्वैपिंग, आदि की आवश्यकता होती है; और वह कुछ ऐसा नहीं है जिसे आप JS में नियंत्रित कर सकते हैं (यानी आप ब्राउज़र की दया पर हैं) 2) यदि आप CPU गहन कार्य करना चाहते हैं तो JS सबसे अच्छी भाषा नहीं है। इसके बजाय C का उपयोग करने पर विचार करें। C
Aadit M Shah

1
यह एक अच्छा बिंदु है और सिंथेटिक बनाम वास्तविक विश्व बेंचमार्किंग के बीच अंतर लाता है। मैं वर्तमान अनुकूलित जेएस के प्रदर्शन से खुश हूं, इसलिए सी। का उपयोग करने की कोई आवश्यकता नहीं है
लुइस रिक्की

इस कार्यान्वयन में एक प्रोटोटाइप प्रदूषण बग भी है, जैसेunflatten({"foo.__proto__.bar": 42})
एलेक्स ब्रासेविक

12

3 later साल बाद ...

अपने स्वयं के प्रोजेक्ट के लिए मैं JSON ऑब्जेक्ट्स को mongoDB डॉट नोटेशन में समतल करना चाहता था और एक सरल समाधान के साथ आया:

/**
 * Recursively flattens a JSON object using dot notation.
 *
 * NOTE: input must be an object as described by JSON spec. Arbitrary
 * JS objects (e.g. {a: () => 42}) may result in unexpected output.
 * MOREOVER, it removes keys with empty objects/arrays as value (see
 * examples bellow).
 *
 * @example
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e': 3, 'b.1': 4}
 * flatten({a: 1, b: [{c: 2, d: {e: 3}}, 4]})
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e.0': true, 'b.0.d.e.1': false, 'b.0.d.e.2.f': 1}
 * flatten({a: 1, b: [{c: 2, d: {e: [true, false, {f: 1}]}}]})
 * // return {a: 1}
 * flatten({a: 1, b: [], c: {}})
 *
 * @param obj item to be flattened
 * @param {Array.string} [prefix=[]] chain of prefix joined with a dot and prepended to key
 * @param {Object} [current={}] result of flatten during the recursion
 *
 * @see https://docs.mongodb.com/manual/core/document/#dot-notation
 */
function flatten (obj, prefix, current) {
  prefix = prefix || []
  current = current || {}

  // Remember kids, null is also an object!
  if (typeof (obj) === 'object' && obj !== null) {
    Object.keys(obj).forEach(key => {
      this.flatten(obj[key], prefix.concat(key), current)
    })
  } else {
    current[prefix.join('.')] = obj
  }

  return current
}

सुविधाएँ और / या चेतावनी

  • यह केवल JSON ऑब्जेक्ट्स को स्वीकार करता है। इसलिए यदि आप कुछ ऐसा {a: () => {}}कर लेते हैं जो आपको वह नहीं मिलता जो आप चाहते थे!
  • यह खाली सरणियों और वस्तुओं को निकालता है। तो यह {a: {}, b: []}चपटा है {}

1
अच्छा है, लेकिन मैं बच गए उद्धरण का ध्यान नहीं रखता। तो {"x": "abc\"{x}\"yz"}वह बन जाता है { "x": "abc"{,"x",}"yz"}जो अविचलित है।
Simsteve7

@ Simsteve7 तुम सही हो! कुछ ऐसा जो मैं हमेशा भूल जाता हूँ!
यान फोटो

11

ES6 संस्करण:

const flatten = (obj, path = '') => {        
    if (!(obj instanceof Object)) return {[path.replace(/\.$/g, '')]:obj};

    return Object.keys(obj).reduce((output, key) => {
        return obj instanceof Array ? 
             {...output, ...flatten(obj[key], path +  '[' + key + '].')}:
             {...output, ...flatten(obj[key], path + key + '.')};
    }, {});
}

उदाहरण:

console.log(flatten({a:[{b:["c","d"]}]}));
console.log(flatten([1,[2,[3,4],5],6]));

1
मुझे लगता है कि अगर आपके पास JSON.stringify (फ़्लैटेन ({"prop1": 0, "prop2": {"prop3"): true, "prop4": "टेस्ट" के नाम के बीच विभाजक नहीं है, तो आपको कुछ कठिनाई हो सकती है। "}})); ==> {"Prop1": 0, "prop2prop3": true, "prop2prop4": "test"} लेकिन लेकिन एक आसान समाधान है, ES6 वाक्यविन्यास की संक्षिप्तता वास्तव में बहुत अच्छी है
लुईस

यह बहुत सही है, अलगाववादियों ने कहा
गाय

यह अच्छी तरह से नहीं खेलता है Date, किसी भी विचार यह करने के लिए कैसे प्राप्त करें? उदाहरण के लिए, साथflatten({a: {b: new Date()}});
एहतेश चौधरी

आप टाइमस्टैम्प का उपयोग कर सकते हैं: {b: नई तिथि ()। GetTime ()}} और बाद में इसे नई तिथि (टाइमस्टैम्प) के साथ वापस भेज दें
लड़के

6

यहां एक और दृष्टिकोण है जो उपरोक्त उत्तर की तुलना में धीमी (लगभग 1000ms) चलता है, लेकिन एक दिलचस्प विचार है :-)

प्रत्येक संपत्ति श्रृंखला के माध्यम से पुनरावृत्ति करने के बजाय, यह केवल अंतिम संपत्ति चुनता है और मध्यवर्ती परिणामों को संग्रहीत करने के लिए बाकी के लिए एक लुक-अप-टेबल का उपयोग करता है। यह लुक-अप-टेबल तब तक पुनरावृत्त हो जाएगी, जब तक कि कोई संपत्ति श्रृंखला नहीं बची हो और सभी मूल्य असंबद्ध गुणों पर रहते हों।

JSON.unflatten = function(data) {
    "use strict";
    if (Object(data) !== data || Array.isArray(data))
        return data;
    var regex = /\.?([^.\[\]]+)$|\[(\d+)\]$/,
        props = Object.keys(data),
        result, p;
    while(p = props.shift()) {
        var m = regex.exec(p),
            target;
        if (m.index) {
            var rest = p.slice(0, m.index);
            if (!(rest in data)) {
                data[rest] = m[2] ? [] : {};
                props.push(rest);
            }
            target = data[rest];
        } else {
            target = result || (result = (m[2] ? [] : {}));
        }
        target[m[2] || m[1]] = data[p];
    }
    return result;
};

यह वर्तमान dataमें तालिका के लिए इनपुट पैरामीटर का उपयोग करता है , और उस पर बहुत सारे गुण डालता है - एक गैर-विनाशकारी संस्करण भी संभव होना चाहिए। हो सकता है कि एक चतुर lastIndexOfउपयोग रेगेक्स (रेगेक्स इंजन पर निर्भर करता है) से बेहतर प्रदर्शन करता है।

इसे यहां कार्रवाई में देखें


मैंने आपके उत्तर को अस्वीकार नहीं किया। हालाँकि, मैं यह बताना चाहूंगा कि आपका फ़ंक्शन unflattenसही ढंग से चपटा वस्तु नहीं है। उदाहरण के लिए सरणी पर विचार करें [1,[2,[3,4],5],6]। आपका flattenकार्य इस ऑब्जेक्ट को समतल करता है {"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}। आपका unflattenकार्य हालांकि गलत तरीके से चपटा वस्तु को अनफ्लैट करता है [1,[null,[3,4]],6]। ऐसा होने का कारण उस कथन के कारण है delete data[p]जो समय [2,null,5]से पहले मध्यवर्ती मान को हटा देता है, [3,4]उसे इसमें जोड़ा जाता है। इसे हल करने के लिए एक स्टैक का उपयोग करें। :-)
आदित एम शाह

1
आह, मैं देख रहा हूँ, अपरिभाषित गणना आदेश ... गुणों की एक कतार के साथ इसे ठीक कर सकते हैं, कृपया अपने स्टैक समाधान को स्वयं के उत्तर में डालें। संकेत के लिए धन्यवाद!
बरगी

4

आप https://github.com/hughsk/flat का उपयोग कर सकते हैं

नेस्टेड जावास्क्रिप्ट ऑब्जेक्ट लें और इसे समतल करें, या सीमांकित कुंजियों के साथ ऑब्जेक्ट को अनफ्लैट करें।

डॉक्टर से उदाहरण

var flatten = require('flat')

flatten({
    key1: {
        keyA: 'valueI'
    },
    key2: {
        keyB: 'valueII'
    },
    key3: { a: { b: { c: 2 } } }
})

// {
//   'key1.keyA': 'valueI',
//   'key2.keyB': 'valueII',
//   'key3.a.b.c': 2
// }


var unflatten = require('flat').unflatten

unflatten({
    'three.levels.deep': 42,
    'three.levels': {
        nested: true
    }
})

// {
//     three: {
//         levels: {
//             deep: 42,
//             nested: true
//         }
//     }
// }

1
आप इसका उपयोग AngularJS में कैसे करते हैं?
22

2

यह कोड पुन: JSON ऑब्जेक्ट्स को समतल करता है।

मैंने अपने समय तंत्र को कोड में शामिल किया और यह मुझे 1ms देता है लेकिन मुझे यकीन नहीं है कि यह सबसे सटीक है।

            var new_json = [{
              "name": "fatima",
              "age": 25,
              "neighbour": {
                "name": "taqi",
                "location": "end of the street",
                "property": {
                  "built in": 1990,
                  "owned": false,
                  "years on market": [1990, 1998, 2002, 2013],
                  "year short listed": [], //means never
                }
              },
              "town": "Mountain View",
              "state": "CA"
            },
            {
              "name": "qianru",
              "age": 20,
              "neighbour": {
                "name": "joe",
                "location": "opposite to the park",
                "property": {
                  "built in": 2011,
                  "owned": true,
                  "years on market": [1996, 2011],
                  "year short listed": [], //means never
                }
              },
              "town": "Pittsburgh",
              "state": "PA"
            }]

            function flatten(json, flattened, str_key) {
                for (var key in json) {
                  if (json.hasOwnProperty(key)) {
                    if (json[key] instanceof Object && json[key] != "") {
                      flatten(json[key], flattened, str_key + "." + key);
                    } else {
                      flattened[str_key + "." + key] = json[key];
                    }
                  }
                }
            }

        var flattened = {};
        console.time('flatten'); 
        flatten(new_json, flattened, "");
        console.timeEnd('flatten');

        for (var key in flattened){
          console.log(key + ": " + flattened[key]);
        }

आउटपुट:

flatten: 1ms
.0.name: fatima
.0.age: 25
.0.neighbour.name: taqi
.0.neighbour.location: end of the street
.0.neighbour.property.built in: 1990
.0.neighbour.property.owned: false
.0.neighbour.property.years on market.0: 1990
.0.neighbour.property.years on market.1: 1998
.0.neighbour.property.years on market.2: 2002
.0.neighbour.property.years on market.3: 2013
.0.neighbour.property.year short listed: 
.0.town: Mountain View
.0.state: CA
.1.name: qianru
.1.age: 20
.1.neighbour.name: joe
.1.neighbour.location: opposite to the park
.1.neighbour.property.built in: 2011
.1.neighbour.property.owned: true
.1.neighbour.property.years on market.0: 1996
.1.neighbour.property.years on market.1: 2011
.1.neighbour.property.year short listed: 
.1.town: Pittsburgh
.1.state: PA

1
मुझे लगता है, typeof some === 'object'यह तेजी से तब some instanceof Objectसे है जब पहला चेक O1 में प्रदर्शन करता है, जबकि दूसरा ऑन एन जहां एक वंशानुक्रम श्रृंखला की लंबाई होती है (ऑब्जेक्ट हमेशा वहां आखिरी होगा)।
गुलेरिया

1

मैंने फ़ंक्शन नाम स्थान के बाहर पुनरावर्ती फ़ंक्शन को मामूली कोड रीफ़ैक्टरिंग और स्थानांतरित करके चयनित उत्तर के लिए +/- 10-15% दक्षता जोड़ी।

मेरा प्रश्न देखें: क्या प्रत्येक कॉल पर नामांकित कार्य फिर से किए गए हैं? इस कारण से यह कार्य धीमा हो जाता है।

function _flatten (target, obj, path) {
  var i, empty;
  if (obj.constructor === Object) {
    empty = true;
    for (i in obj) {
      empty = false;
      _flatten(target, obj[i], path ? path + '.' + i : i);
    }
    if (empty && path) {
      target[path] = {};
    }
  } 
  else if (obj.constructor === Array) {
    i = obj.length;
    if (i > 0) {
      while (i--) {
        _flatten(target, obj[i], path + '[' + i + ']');
      }
    } else {
      target[path] = [];
    }
  }
  else {
    target[path] = obj;
  }
}

function flatten (data) {
  var result = {};
  _flatten(result, data, null);
  return result;
}

बेंचमार्क देखें ।


1

ये मेरा। यह Google ऐप्स स्क्रिप्ट में <2ms एक बड़े आकार की वस्तु पर चलता है। यह विभाजकों के लिए डॉट्स के बजाय डैश का उपयोग करता है, और यह विशेष रूप से पूछने वाले के सवाल की तरह सरणियों को संभाल नहीं करता है, लेकिन यह वही है जो मैं अपने उपयोग के लिए चाहता था।

function flatten (obj) {
  var newObj = {};
  for (var key in obj) {
    if (typeof obj[key] === 'object' && obj[key] !== null) {
      var temp = flatten(obj[key])
      for (var key2 in temp) {
        newObj[key+"-"+key2] = temp[key2];
      }
    } else {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

उदाहरण:

var test = {
  a: 1,
  b: 2,
  c: {
    c1: 3.1,
    c2: 3.2
  },
  d: 4,
  e: {
    e1: 5.1,
    e2: 5.2,
    e3: {
      e3a: 5.31,
      e3b: 5.32
    },
    e4: 5.4
  },
  f: 6
}

Logger.log("start");
Logger.log(JSON.stringify(flatten(test),null,2));
Logger.log("done");

उदाहरण आउटपुट:

[17-02-08 13:21:05:245 CST] start
[17-02-08 13:21:05:246 CST] {
  "a": 1,
  "b": 2,
  "c-c1": 3.1,
  "c-c2": 3.2,
  "d": 4,
  "e-e1": 5.1,
  "e-e2": 5.2,
  "e-e3-e3a": 5.31,
  "e-e3-e3b": 5.32,
  "e-e4": 5.4,
  "f": 6
}
[17-02-08 13:21:05:247 CST] done

1

इस पुस्तकालय का उपयोग करें:

npm install flat

उपयोग ( https://www.npmjs.com/package/flat से ):

समतल:

    var flatten = require('flat')


    flatten({
        key1: {
            keyA: 'valueI'
        },
        key2: {
            keyB: 'valueII'
        },
        key3: { a: { b: { c: 2 } } }
    })

    // {
    //   'key1.keyA': 'valueI',
    //   'key2.keyB': 'valueII',
    //   'key3.a.b.c': 2
    // }

संयुक्त राष्ट्र के समतल:

var unflatten = require('flat').unflatten

unflatten({
    'three.levels.deep': 42,
    'three.levels': {
        nested: true
    }
})

// {
//     three: {
//         levels: {
//             deep: 42,
//             nested: true
//         }
//     }
// }

2
अपने उत्तर को पूरा करने के लिए आपको उस पुस्तकालय का उपयोग करने का एक उदाहरण जोड़ना चाहिए।
एंटोनियो अल्मेडा

0

मैं समतल केस का एक नया संस्करण जोड़ना चाहूंगा (यह वही है जिसकी मुझे आवश्यकता है :)), जो कि उपरोक्त jsFiddler के साथ मेरी जांच के अनुसार, थोड़ा तेज है, फिर वर्तमान में चयनित है। इसके अलावा, मैं व्यक्तिगत रूप से इस स्निपेट को थोड़ा अधिक पठनीय देखता हूं, जो बहु-डेवलपर परियोजनाओं के लिए निश्चित रूप से महत्वपूर्ण है।

function flattenObject(graph) {
    let result = {},
        item,
        key;

    function recurr(graph, path) {
        if (Array.isArray(graph)) {
            graph.forEach(function (itm, idx) {
                key = path + '[' + idx + ']';
                if (itm && typeof itm === 'object') {
                    recurr(itm, key);
                } else {
                    result[key] = itm;
                }
            });
        } else {
            Reflect.ownKeys(graph).forEach(function (p) {
                key = path + '.' + p;
                item = graph[p];
                if (item && typeof item === 'object') {
                    recurr(item, key);
                } else {
                    result[key] = item;
                }
            });
        }
    }
    recurr(graph, '');

    return result;
}

0

यहाँ कुछ कोड है, जो मैंने उस वस्तु को समतल करने के लिए लिखा है, जिसके साथ मैं काम कर रहा था। यह एक नया वर्ग बनाता है जो प्रत्येक नेस्टेड फ़ील्ड को लेता है और इसे पहली परत में लाता है। आप कुंजी के मूल स्थान को याद करके इसे अनफ़्लैट कर सकते हैं। यह भी माना जाता है कि नेस्टेड ऑब्जेक्ट्स में भी कुंजियाँ अद्वितीय हैं। आशा करता हूँ की ये काम करेगा।

class JSONFlattener {
    ojson = {}
    flattenedjson = {}

    constructor(original_json) {
        this.ojson = original_json
        this.flattenedjson = {}
        this.flatten()
    }

    flatten() {
        Object.keys(this.ojson).forEach(function(key){
            if (this.ojson[key] == null) {

            } else if (this.ojson[key].constructor == ({}).constructor) {
                this.combine(new JSONFlattener(this.ojson[key]).returnJSON())
            } else {
                this.flattenedjson[key] = this.ojson[key]
            }
        }, this)        
    }

    combine(new_json) {
        //assumes new_json is a flat array
        Object.keys(new_json).forEach(function(key){
            if (!this.flattenedjson.hasOwnProperty(key)) {
                this.flattenedjson[key] = new_json[key]
            } else {
                console.log(key+" is a duplicate key")
            }
        }, this)
    }

    returnJSON() {
        return this.flattenedjson
    }
}

console.log(new JSONFlattener(dad_dictionary).returnJSON())

एक उदाहरण के रूप में, यह धर्मान्तरित

nested_json = {
    "a": {
        "b": {
            "c": {
                "d": {
                    "a": 0
                }
            }
        }
    },
    "z": {
        "b":1
    },
    "d": {
        "c": {
            "c": 2
        }
    }
}

में

{ a: 0, b: 1, c: 2 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.