স্থায়ীভাবে নেস্টেড অবজেক্টের সম্পত্তি সেট করুন


89

আমার কাছে একটি অবজেক্ট রয়েছে যা অনেকগুলি স্তর গভীর হতে পারে এবং যে কোনও বিদ্যমান বৈশিষ্ট্য থাকতে পারে। উদাহরণ স্বরূপ:

var obj = {
    db: {
        mongodb: {
            host: 'localhost'
        }
    }
};

তারপরে আমি এর মতো বৈশিষ্ট্যগুলি (বা ওভাররাইট) সেট করতে চাই:

set('db.mongodb.user', 'root');
// or:
set('foo.bar', 'baz');

যেখানে সম্পত্তি স্ট্রিংয়ের কোনও গভীরতা থাকতে পারে এবং মানটি কোনও প্রকার / জিনিস হতে পারে।
মান হিসাবে বস্তু এবং অ্যারেগুলি মার্জ করার দরকার নেই, সম্পত্তি কীটি ইতিমধ্যে উপস্থিত থাকলে।

পূর্ববর্তী উদাহরণ নিম্নলিখিত বস্তু উত্পাদন করতে হবে:

var obj = {
    db: {
        mongodb: {
            host: 'localhost',
            user: 'root'
        }
    },
    foo: {
        bar: baz
    }
};

আমি কিভাবে এই ধরনের একটি ফাংশন বুঝতে পারি?


ফলাফলটি কী হওয়া উচিত set('foo', 'bar'); set('foo.baz', 'qux');, যেখানে fooপ্রথমে একটি Stringপরে থাকে তার হয়ে যায় Object? কি হয় 'bar'?
জোনাথন লোনোস্কি


এই সহায়তাটি সক্ষম হতে পারে: স্ট্যাকওভারফ্লো
রিনি এম

4
আপনি যদি set()পদ্ধতিটি সরিয়ে থাকেন এবং কেবল obj.db.mongodb.user = 'root';আপনি চান যা মনে হচ্ছে ঠিক তেমন চান?
অ্যাডিনিও

@JonathanLonowski Lonowski barদ্বারা ওভাররাইট পায় Object। @ অ্যাডিনিও এবং @ রিমার্টিনস প্রকৃতপক্ষে :) তবে দুর্ভাগ্যক্রমে আমাকে আরও কিছু যুক্তি গুটিয়ে রাখতে হয়েছে। @ রবার্ট লেভী আমি এটি পেয়েছি এবং অ্যাক্সেসিংয়ের কাজ পেয়েছি তবে এটি সেট করা আরও জটিল বলে মনে হচ্ছে ...
জন বি।

উত্তর:


98

এই ফাংশনটি, আপনার নির্দিষ্ট করা যুক্তিগুলি ব্যবহার করে, objপাত্রে ডেটা যুক্ত করা / আপডেট করা উচিত । নোট করুন যে objস্কিমাতে কোন উপাদানগুলি পাত্রে রয়েছে এবং কোনটি মানগুলি (স্ট্রিং, ইনটস ইত্যাদি) তা ট্র্যাক করে রাখতে হবে অন্যথায় আপনি ব্যতিক্রম ছোঁড়া শুরু করবেন।

obj = {};  // global object

function set(path, value) {
    var schema = obj;  // a moving reference to internal objects within obj
    var pList = path.split('.');
    var len = pList.length;
    for(var i = 0; i < len-1; i++) {
        var elem = pList[i];
        if( !schema[elem] ) schema[elem] = {}
        schema = schema[elem];
    }

    schema[pList[len-1]] = value;
}

set('mongo.db.user', 'root');

4
@ বিপিএমসন var schema = obj1 আপনি কেবলমাত্র objসর্বত্র পরিবর্তে কেন ব্যবহার করেছেন তা ব্যাখ্যা করতে পারেন ?
sman591

4
@ sman591 schemaএকটি পয়েন্টার যা দিয়ে পথে সরানো হয় schema = schema[elem]। সুতরাং লুপের পরে, schema[pList[len - 1]]mongo.db.user এ পয়েন্ট করুন obj
ওয়েবজয়

যা আমার সমস্যার সমাধান করেছে ধন্যবাদ, এটি এমডিএন ডক্সে খুঁজে পেল না। তবে আমার আরেকটি সন্দেহ রয়েছে, যদি অ্যাসাইনমেন্ট অপারেটর অভ্যন্তরীণ অবজেক্টগুলিকে একটি রেফারেন্স দেয় তবে কীভাবে অবজেক্ট 1 থেকে পৃথক অবজেক্ট 2 তৈরি করা যায় যাতে অবজেক্ট 2 এ করা পরিবর্তনগুলি বস্তু 1 তে প্রতিফলিত হয় না।
অনিক্স

@ অনিক্স আপনি এর জন্য লোডাশ cloneDeepফাংশনটি ব্যবহার করতে পারেন ।
আকাশ ঠাকুর

@ অনিক্স কনস্ট ক্লোন = JSON.parse (JSON.stringify (obj))
মাইক মাকুচ

79

লোড্যাশের একটি _.set () পদ্ধতি রয়েছে।

_.set(obj, 'db.mongodb.user', 'root');
_.set(obj, 'foo.bar', 'baz');

4
এটি কী কী হিসাবে মান সেট করতে ব্যবহার করা যেতে পারে? যদি হ্যাঁ আপনি একটি উদাহরণ ভাগ করতে পারেন। আপনাকে ধন্যবাদ
ষি পডেল

এটি দুর্দান্ত, তবে আপনি কীভাবে পথটিকে লক্ষ্য রাখবেন / নির্ধারণ করবেন?
টম

19

কিছুটা দেরি হলেও এখানে একটি গ্রন্থাগারহীন, সহজ উত্তর:

/**
 * Dynamically sets a deeply nested value in an object.
 * Optionally "bores" a path to it if its undefined.
 * @function
 * @param {!object} obj  - The object which contains the value you want to change/set.
 * @param {!array} path  - The array representation of path to the value you want to change/set.
 * @param {!mixed} value - The value you want to set it to.
 * @param {boolean} setrecursively - If true, will set value of non-existing path as well.
 */
function setDeep(obj, path, value, setrecursively = false) {
    path.reduce((a, b, level) => {
        if (setrecursively && typeof a[b] === "undefined" && level !== path.length){
            a[b] = {};
            return a[b];
        }

        if (level === path.length){
            a[b] = value;
            return value;
        } 
        return a[b];
    }, obj);
}

আমি তৈরি এই ফাংশনটি আপনার যা প্রয়োজন ঠিক তা করতে পারে এবং আরও অনেক কিছু করতে পারে।

আসুন আমরা এই লক্ষ্যটিতে গভীরভাবে বাসা বাঁধে লক্ষ্য মানটি পরিবর্তন করতে চাই তা বলি:

let myObj = {
    level1: {
        level2: {
           target: 1
       }
    }
}

সুতরাং আমরা আমাদের ফাংশনকে এভাবে কল করব:

setDeep(myObj, ["level1", "level2", "target1"], 3);

ফলাফল হবে:

myObj = {স্তর 1: {স্তর 2: {লক্ষ্য: 3}}}

সেটটি পুনরাবৃত্তভাবে পতাকাটিকে সত্যতে সেট করা যদি বস্তুগুলির অস্তিত্ব না থাকে তবে সেট করে।

setDeep(myObj, ["new", "path", "target"], 3, true);

এর ফলস্বরূপ:

obj = myObj = {
    new: {
         path: {
             target: 3
         }
    },
    level1: {
        level2: {
           target: 3
       }
    }
}

4
পরিষ্কার এবং সহজ এই কোডটি ব্যবহার করুন। কম্পিউটিংয়ের পরিবর্তে levelআমি reduceতৃতীয় যুক্তি ব্যবহার করেছি ।
জুয়ান ল্যানাস

4
আমি বিশ্বাস করি যে level+1 বা path.length-1 হওয়া দরকার
টমাসরেগি

12

আমরা একটি পুনরাবৃত্তি ফাংশন ব্যবহার করতে পারি:

/**
 * Sets a value of nested key string descriptor inside a Object.
 * It changes the passed object.
 * Ex:
 *    let obj = {a: {b:{c:'initial'}}}
 *    setNestedKey(obj, ['a', 'b', 'c'], 'changed-value')
 *    assert(obj === {a: {b:{c:'changed-value'}}})
 *
 * @param {[Object]} obj   Object to set the nested key
 * @param {[Array]} path  An array to describe the path(Ex: ['a', 'b', 'c'])
 * @param {[Object]} value Any value
 */
export const setNestedKey = (obj, path, value) => {
  if (path.length === 1) {
    obj[path] = value
    return
  }
  return setNestedKey(obj[path[0]], path.slice(1), value)
}

এটা আরও সহজ!


4
ভাল লাগছে! এটি মিথ্যা নয় তা নিশ্চিত করার জন্য কেবল ওজেক্ট প্যারামটি পরীক্ষা করা দরকার, যদি চেইনের নিচে কোনও প্রপস উপস্থিত না থাকে তবে একটি ত্রুটি ফেলবে।
সি স্মিথ

4
আপনি কেবল path.slice (1) ব্যবহার করতে পারেন;
মার্কোস পেরেইরা

4
দুর্দান্ত উত্তর, একটি দুর্দান্ত এবং সংক্ষিপ্ত সমাধান।
চিম

আমি বিশ্বাস করি যদি বিবৃতিটি হয় তবে এটি হওয়া উচিত ছিল obj[path[0]] = value;কারণ pathসর্বদা টাইপ থাকে string[], এমনকি যখন কেবল 1 টি স্ট্রিং থাকে।
মূল্যবান

জাভাস্ক্রিপ্ট অবজেক্ট ব্যবহার করে কাজ করা উচিত obj[['a']] = 'new value' । কোডটি দেখুন: jsfiddle.net/upsdne03
হেমি ভিডাল

12

আমি লক্ষ্য অর্জনের জন্য কেবল ES6 + রিকার্সন ব্যবহার করে একটি ছোট ফাংশন লিখি।

updateObjProp = (obj, value, propPath) => {
    const [head, ...rest] = propPath.split('.');

    !rest.length
        ? obj[head] = value
        : this.updateObjProp(obj[head], value, rest.join('.'));
}

const user = {profile: {name: 'foo'}};
updateObjProp(user, 'fooChanged', 'profile.name');

রাষ্ট্র আপডেট করার জন্য আমি এটিকে অনেক প্রতিক্রিয়া জানিয়েছিলাম, এটি আমার পক্ষে বেশ ভাল কাজ করেছে।


4
এটি সুবিধাজনক ছিল, নেস্টেড বৈশিষ্ট্যগুলির সাথে এটির কাজ করার জন্য আমাকে প্রোপ্যাথে একটি স্ট্রিং () রাখতে হয়েছিল, তবে এর পরে এটি দুর্দান্ত কাজ করেছে। কনস্ট [হেড, ... রেস্ট] = প্রোপথ.টোস্ট্রিং ()। বিভক্ত ('।');
উইজার্ডস অফ ওয়ার

4
@ ইউজার 80৮০৮৮ @ ব্রুনো-জোউকিম লাইনটি this.updateStateProp(obj[head], value, rest);হওয়া উচিতthis.updateStateProp(obj[head], value, rest.join());
ma.mehralian

9

ES6 এর খুব কমপিউটেড প্রোপার্টি নেম এবং রেস্ট প্যারামিটার ব্যবহার করে এটি করার দুর্দান্ত উপায় রয়েছে ।

const obj = {
  levelOne: {
    levelTwo: {
      levelThree: "Set this one!"
    }
  }
}

const updatedObj = {
  ...obj,
  levelOne: {
    ...obj.levelOne,
    levelTwo: {
      ...obj.levelOne.levelTwo,
      levelThree: "I am now updated!"
    }
  }
}

যদি levelThreeকোনও গতিশীল সম্পত্তি থাকে তবে কোনও সম্পত্তি সেট করার জন্য levelTwo, আপনি [propertyName]: "I am now updated!"যেখানে propertyNameসম্পত্তিটির নাম ধারণ করে সেখানে ব্যবহার করতে পারেন levelTwo


8

@ বিপিএমসন 1 এর উত্তরে অনুপ্রাণিত:

function leaf(obj, path, value) {
  const pList = path.split('.');
  const key = pList.pop();
  const pointer = pList.reduce((accumulator, currentValue) => {
    if (accumulator[currentValue] === undefined) accumulator[currentValue] = {};
    return accumulator[currentValue];
  }, obj);
  pointer[key] = value;
  return obj;
}

উদাহরণ:

const obj = {
  boats: {
    m1: 'lady blue'
  }
};
leaf(obj, 'boats.m1', 'lady blue II');
leaf(obj, 'boats.m2', 'lady bird');
console.log(obj); // { boats: { m1: 'lady blue II', m2: 'lady bird' } }

7

লোড্যাশের আপডেট নামক একটি পদ্ধতি রয়েছে যা আপনার প্রয়োজন মতো করে does

এই পদ্ধতিটি নিম্নলিখিত পরামিতিগুলি গ্রহণ করে:

  1. আপডেট করার জন্য অবজেক্ট
  2. সম্পত্তি আপডেট করার পথ (সম্পত্তি গভীরভাবে বাসা বাঁধতে পারে)
  3. একটি ফাংশন যা আপডেট করার জন্য মানটি ফেরত দেয় (প্যারামিটার হিসাবে মূল মান দেওয়া হয়)

আপনার উদাহরণে এটি দেখতে এই রকম হবে:

_.update(obj, 'db.mongodb.user', function(originalValue) {
  return 'root'
})

2

আমার তৈরি সারকথা সেটিং এবং সঠিক উত্তরটি উপর ভিত্তি করে স্ট্রিং দ্বারা মান obj পাবার জন্য। আপনি এটিকে ডাউনলোড বা এনপিএম / সুতার প্যাকেজ হিসাবে ব্যবহার করতে পারেন।

// yarn add gist:5ceba1081bbf0162b98860b34a511a92
// npm install gist:5ceba1081bbf0162b98860b34a511a92
export const DeepObject = {
  set: setDeep,
  get: getDeep
};

// https://stackoverflow.com/a/6491621
function getDeep(obj: Object, path: string) {
  path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
  path = path.replace(/^\./, '');           // strip a leading dot
  const a = path.split('.');
  for (let i = 0, l = a.length; i < l; ++i) {
    const n = a[i];
    if (n in obj) {
      obj = obj[n];
    } else {
      return;
    }
  }

  return obj;
}

// https://stackoverflow.com/a/18937118
function setDeep(obj: Object, path: string, value: any) {
  let schema = obj;  // a moving reference to internal objects within obj
  const pList = path.split('.');
  const len = pList.length;
  for (let i = 0; i < len - 1; i++) {
    const elem = pList[i];
    if (!schema[elem]) {
      schema[elem] = {};
    }
    schema = schema[elem];
  }

  schema[pList[len - 1]] = value;
}

// Usage
// import {DeepObject} from 'somePath'
//
// const obj = {
//   a: 4,
//   b: {
//     c: {
//       d: 2
//     }
//   }
// };
//
// DeepObject.set(obj, 'b.c.d', 10); // sets obj.b.c.d to 10
// console.log(DeepObject.get(obj, 'b.c.d')); // returns 10

1

আপনার যদি কেবল গভীর নেস্টেড অবজেক্টগুলি পরিবর্তন করতে হয় তবে অন্য পদ্ধতিটি অবজেক্টটি উল্লেখ করা যেতে পারে। যেহেতু জেএস বিষয়বস্তুগুলি তাদের রেফারেন্সগুলি দ্বারা পরিচালিত হয়, আপনি স্ট্রিং-কী অ্যাক্সেসের কোনও অবজেক্টের জন্য একটি রেফারেন্স তৈরি করতে পারেন।

উদাহরণ:

// The object we want to modify:
var obj = {
    db: {
        mongodb: {
            host: 'localhost',
            user: 'root'
        }
    },
    foo: {
        bar: baz
    }
};

var key1 = 'mongodb';
var key2 = 'host';

var myRef = obj.db[key1]; //this creates a reference to obj.db['mongodb']

myRef[key2] = 'my new string';

// The object now looks like:
var obj = {
    db: {
        mongodb: {
            host: 'my new string',
            user: 'root'
        }
    },
    foo: {
        bar: baz
    }
};

1

আর একটি পদ্ধতি হ'ল অবজেক্টটি খনন করতে পুনরাবৃত্তি ব্যবহার করা:

(function(root){

  function NestedSetterAndGetter(){
    function setValueByArray(obj, parts, value){

      if(!parts){
        throw 'No parts array passed in';
      }

      if(parts.length === 0){
        throw 'parts should never have a length of 0';
      }

      if(parts.length === 1){
        obj[parts[0]] = value;
      } else {
        var next = parts.shift();

        if(!obj[next]){
          obj[next] = {};
        }
        setValueByArray(obj[next], parts, value);
      }
    }

    function getValueByArray(obj, parts, value){

      if(!parts) {
        return null;
      }

      if(parts.length === 1){
        return obj[parts[0]];
      } else {
        var next = parts.shift();

        if(!obj[next]){
          return null;
        }
        return getValueByArray(obj[next], parts, value);
      }
    }

    this.set = function(obj, path, value) {
      setValueByArray(obj, path.split('.'), value);
    };

    this.get = function(obj, path){
      return getValueByArray(obj, path.split('.'));
    };

  }
  root.NestedSetterAndGetter = NestedSetterAndGetter;

})(this);

var setter = new this.NestedSetterAndGetter();

var o = {};
setter.set(o, 'a.b.c', 'apple');
console.log(o); //=> { a: { b: { c: 'apple'}}}

var z = { a: { b: { c: { d: 'test' } } } };
setter.set(z, 'a.b.c', {dd: 'zzz'}); 

console.log(JSON.stringify(z)); //=> {"a":{"b":{"c":{"dd":"zzz"}}}}
console.log(JSON.stringify(setter.get(z, 'a.b.c'))); //=> {"dd":"zzz"}
console.log(JSON.stringify(setter.get(z, 'a.b'))); //=> {"c":{"dd":"zzz"}}

1

আমার একই জিনিসটি অর্জন করা দরকার, তবে নোড.জেজে ... সুতরাং, আমি এই দুর্দান্ত মডিউলটি পেয়েছি: https://www.npmjs.com/package/nested-property

উদাহরণ:

var mod = require("nested-property");
var obj = {
  a: {
    b: {
      c: {
        d: 5
      }
    }
  }
};
console.log(mod.get(obj, "a.b.c.d"));
mod.set(obj, "a.b.c.d", 6);
console.log(mod.get(obj, "a.b.c.d"));

জটিল নেস্টেড জিনিসগুলির জন্য কীভাবে সমাধান করবেন। `` `কনট এক্স = {'এক': 1, 'দুই': 2, 'তিন': one 'এক': 1, 'দুই': 2, 'তিন': [{'এক': 1}, { 'এক': 'এক'}, {'এক': 'আমি'}]}, 'চার': [0, 1, 2]}; কনসোল.লগ (এনপি.জেট (এক্স, 'থ্রি.থ্রি [0] .ওন')); `` `
সুমুখা এইচএস

1

আমি খাঁটি এস 6 এবং পুনরাবৃত্তি ব্যবহার করে আমার নিজের সমাধানটি নিয়ে এসেছি যা আসল বস্তুকে রূপান্তরিত করে না।

const setNestedProp = (obj = {}, [first, ...rest] , value) => ({
  ...obj,
  [first]: rest.length
    ? setNestedProp(obj[first], rest, value)
    : value
});

const result = setNestedProp({}, ["first", "second", "a"], 
"foo");
const result2 = setNestedProp(result, ["first", "second", "b"], "bar");

console.log(result);
console.log(result2);


ডিফল্ট মান সেটনেসডপ্রেস = (আপত্তি = {keys, কী, মান) => {
ব্লাইন্ড চিকেন

4
হ্যাঁ দুর্দান্ত। পিছনে তাকানো সিটুতে কী কী যুক্তিটি গঠন করতে পারে এবং কোডের অন্য লাইনটি সংরক্ষণ করতে পারে
হেনরি ইং-সিমন্স

মূলত এখন একটি লাইনার 👍
হেনরি ইং-সিমন্স

0

আপনি যদি এমন কোনও ফাংশন চান যা পূর্বের বৈশিষ্ট্যগুলির অস্তিত্বের প্রয়োজন হয়, তবে আপনি এর মতো কিছু ব্যবহার করতে পারেন, এটি একটি পতাকাও প্রত্যাখ্যান করবে যা জানায় যে এটি নেস্টেড সম্পত্তি খুঁজে পেতে এবং সেট করতে সক্ষম হয়েছে কিনা st

function set(obj, path, value) {
    var parts = (path || '').split('.');
    // using 'every' so we can return a flag stating whether we managed to set the value.
    return parts.every((p, i) => {
        if (!obj) return false; // cancel early as we havent found a nested prop.
        if (i === parts.length - 1){ // we're at the final part of the path.
            obj[parts[i]] = value;          
        }else{
            obj = obj[parts[i]]; // overwrite the functions reference of the object with the nested one.            
        }   
        return true;        
    });
}

0

পুনরাবৃত্তিটি ব্যবহার করে ক্লোজার স্ক্রিপ্ট assoc-in( https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L5280 ) দ্বারা অনুপ্রাণিত :

/**
 * Associate value (v) in object/array (m) at key/index (k).
 * If m is falsy, use new object.
 * Returns the updated object/array.
 */
function assoc(m, k, v) {
    m = (m || {});
    m[k] = v;
    return m;
}

/**
 * Associate value (v) in nested object/array (m) using sequence of keys (ks)
 * to identify the path to the nested key/index.
 * If one of the values in the nested object/array doesn't exist, it adds
 * a new object.
 */
function assoc_in(m={}, [k, ...ks], v) {
    return ks.length ? assoc(m, k, assoc_in(m[k], ks, v)) : assoc(m, k, v);
}

/**
 * Associate value (v) in nested object/array (m) using key string notation (s)
 * (e.g. "k1.k2").
 */
function set(m, s, v) {
    ks = s.split(".");
    return assoc_in(m, ks, v);
}

বিঃদ্রঃ:

প্রদত্ত বাস্তবায়নের সাথে,

assoc_in({"a": 1}, ["a", "b"], 2) 

প্রত্যাবর্তন

{"a": 1}

আমি পছন্দ করি এটি এই ক্ষেত্রে একটি ত্রুটি ছুঁড়ে ফেলে। যদি ইচ্ছা হয়, আপনি assocযাচাই করতে একটি চেক ইন যুক্ত করতে পারেন mহয় হয় কোনও বস্তু বা অ্যারে এবং অন্যথায় ত্রুটি নিক্ষেপ করতে পারেন।


0

আমি এই সেট পদ্ধতিটি সংক্ষেপে লেখার চেষ্টা করেছি , এটি কারও সাহায্য করতে পারে!

function set(obj, key, value) {
 let keys = key.split('.');
 if(keys.length<2){ obj[key] = value; return obj; }

 let lastKey = keys.pop();

 let fun = `obj.${keys.join('.')} = {${lastKey}: '${value}'};`;
 return new Function(fun)();
}

var obj = {
"hello": {
    "world": "test"
}
};

set(obj, "hello.world", 'test updated'); 
console.log(obj);

set(obj, "hello.world.again", 'hello again'); 
console.log(obj);

set(obj, "hello.world.again.onece_again", 'hello once again');
console.log(obj);


-1

জিকুয়েরির একটি বর্ধিত পদ্ধতি রয়েছে:

https://api.jquery.com/jquery.extend/

ওভাররাইটগুলি কেবল একটি বস্তুরূপে পাস করুন এবং এটি দুটিকে একত্রী করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.