দুটি বস্তুর মধ্যে জেনেরিক গভীর পার্থক্য


222

আমার দুটি জিনিস আছে: oldObjএবং newObj

এতে থাকা ডেটাগুলি oldObjকোনও ফর্ম তৈরি করতে ব্যবহৃত হয়েছিল এবং newObjএটি ব্যবহারকারী এই ফর্মটিতে ডেটা পরিবর্তন করে এবং এটি জমা দেওয়ার ফলাফল।

উভয় বস্তু গভীর, অর্থাৎ। তাদের বৈশিষ্ট্য যা বস্তু বা বস্তুর অ্যারে ইত্যাদি হয় - সেগুলি এন স্তরগুলি গভীরতর হতে পারে, সুতরাং পৃথক অ্যালগরিদমটি পুনরাবৃত্ত হওয়া দরকার।

এখন আমি শুধু (ইন হিসেবে যোগ / আপডেট / মুছে ফেলা হয়েছে) জিনিসটা না কি পরিবর্তন করা হয়েছে থেকে প্রয়োজন oldObjথেকে newObj, কিন্তু সেরা কিভাবে এটি প্রতিনিধিত্ব করে।

এখনও অবধি আমার চিন্তাভাবনাগুলি কেবল একটি genericDeepDiffBetweenObjectsপদ্ধতি তৈরি করা ছিল যা ফর্মটিতে কোনও বস্তু ফিরিয়ে আনবে {add:{...},upd:{...},del:{...}}তবে আমি ভেবেছিলাম: এর আগে অন্য কারও প্রয়োজন ছিল।

সুতরাং ... কেউ কি এমন কোনও লাইব্রেরি বা কোডের টুকরো সম্পর্কে জানেন যা এটি করবে এবং পার্থক্যটি উপস্থাপনের আরও ভাল উপায় থাকতে পারে (এমনভাবে এখনও জেএসওএন সিরিয়ালযোগ্য)?

হালনাগাদ:

আমি একই তথ্যের কাঠামো ব্যবহার করে আপডেট হওয়া ডেটা উপস্থাপনের আরও ভাল উপায়ের কথা ভেবেছি newObj, তবে সমস্ত সম্পত্তি মানকে ফর্মের বস্তুতে পরিণত করে:

{type: '<update|create|delete>', data: <propertyValue>}

সুতরাং newObj.prop1 = 'new value'এবং যদি oldObj.prop1 = 'old value'এটি সেট হবেreturnObj.prop1 = {type: 'update', data: 'new value'}

আপডেট 2:

অ্যারে [1,2,3]সমেত বৈশিষ্ট্যগুলি পাওয়া গেলে এটি সত্যই লোমশ হয়ে যায়, যেহেতু অ্যারেটি সমান হিসাবে গণনা করা উচিত [2,3,1], যা স্ট্রিং, ইন্ট এবং বুলের মতো মান ভিত্তিক ধরণের অ্যারেগুলির জন্য যথেষ্ট সহজ, তবে এটি আসার সময় হ্যান্ডেল করা সত্যিই কঠিন হয়ে যায় বিষয়বস্তু এবং অ্যারে যেমন রেফারেন্স ধরণের অ্যারে।

সমান হিসাবে পাওয়া উচিত এমন অ্যারেগুলির উদাহরণ:

[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]

এই ধরণের গভীর মান সমতার জন্য যাচাই করা কেবল জটিল নয়, পরিবর্তনের যে পরিবর্তনগুলি হতে পারে সে উপস্থাপনের জন্য একটি ভাল উপায় বের করাও।



2
@ a'r: এটা সদৃশ নয় stackoverflow.com/questions/1200562/... - আমি কিভাবে বস্তু তর্ক করতে জানেন, আমি পূর্বে শিল্প খোঁজ করছি যেহেতু এই অ তুচ্ছ এবং বাস্তবায়ন বাস্তব সময় লাগবে, এবং আমি স্ক্র্যাচ থেকে তৈরি করার চেয়ে কোনও লাইব্রেরি ব্যবহার করবেন না।
মার্টিন জেস্পারসেন

1
আপনার কি সত্যই ভিন্ন অবজেক্টের দরকার আছে, ফর্মের সার্ভার থেকে তৈরি নতুন ওবিজেটি কি প্রতিক্রিয়া জমা দেয়? কারণ আপনার যদি কোনও অবজেক্টের "সার্ভার আপডেট" না থাকে আপনি উপযুক্ত ইভেন্ট শ্রোতাদের সংযুক্ত করে এবং ব্যবহারকারীর ইন্টারঅ্যাকশন (অবজেক্ট চেঞ্জ) এর মাধ্যমে আপনার সমস্যাটি সহজতর করতে পারেন যা আপনাকে ওয়ান্টেড পরিবর্তন তালিকা তৈরি করতে / তৈরি করতে পারে।
sbgoran

1
@sbgoran: জেএস newObjকোড রিডিং মানগুলি ডিওমের একটি ফর্ম থেকে উত্পন্ন হয়। রাষ্ট্র বজায় রাখা এবং এটি আরও সহজ করার কয়েকটি উপায় রয়েছে তবে আমি এটিকে অনুশীলন হিসাবে রাষ্ট্রহীন রাখতে চাই। এছাড়াও আমি পূর্বের শিল্পের সন্ধান করছি যে অন্যরা কীভাবে এটি মোকাবেলা করতে পারে তা যদি সত্যিই কারও কাছে থাকে।
মার্টিন জেসপারসেন

3
জাভাস্ক্রিপ্ট অবজেক্টের যে কোনও জুটির পার্থক্য / প্যাচ করার জন্য এখানে একটি অত্যাধুনিক গ্রন্থাগার রয়েছে github.com/benjamine/jsondiffpatch আপনি এটি এখানে সরাসরি দেখতে পাবেন: benjamine.github.io/jsondiffpatch/demo/index.html (অস্বীকৃতি: আমি লেখক)
বেনজা

উত্তর:


141

আমি একটি সামান্য ক্লাস লিখেছি যা আপনি যা করছেন তা করছেন, আপনি এটি এখানে পরীক্ষা করতে পারেন ।

কেবলমাত্র আপনার প্রস্তাবের থেকে পৃথক জিনিসটি হ'ল আমি [1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]একই হিসাবে বিবেচনা করি না , কারণ আমি মনে করি যে তাদের উপাদানগুলির ক্রম একই না থাকলে অ্যারেগুলি সমান নয়। প্রয়োজনে অবশ্যই এটি পরিবর্তন করা যেতে পারে। এছাড়াও এই কোডটি আর্গুমেন্ট হিসাবে ফাংশন নিতে আরও বাড়ানো যেতে পারে যা উত্তীর্ণ আদিম মানের উপর ভিত্তি করে স্বতন্ত্র পদ্ধতিতে ডিফ ডিগ্রি ফর্ম্যাট করতে ব্যবহৃত হবে (এখন এই কাজটি "তুলনামূলকভাবে" পদ্ধতি দ্বারা সম্পন্ন হয়েছে)।

var deepDiffMapper = function () {
  return {
    VALUE_CREATED: 'created',
    VALUE_UPDATED: 'updated',
    VALUE_DELETED: 'deleted',
    VALUE_UNCHANGED: 'unchanged',
    map: function(obj1, obj2) {
      if (this.isFunction(obj1) || this.isFunction(obj2)) {
        throw 'Invalid argument. Function given, object expected.';
      }
      if (this.isValue(obj1) || this.isValue(obj2)) {
        return {
          type: this.compareValues(obj1, obj2),
          data: obj1 === undefined ? obj2 : obj1
        };
      }

      var diff = {};
      for (var key in obj1) {
        if (this.isFunction(obj1[key])) {
          continue;
        }

        var value2 = undefined;
        if (obj2[key] !== undefined) {
          value2 = obj2[key];
        }

        diff[key] = this.map(obj1[key], value2);
      }
      for (var key in obj2) {
        if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
          continue;
        }

        diff[key] = this.map(undefined, obj2[key]);
      }

      return diff;

    },
    compareValues: function (value1, value2) {
      if (value1 === value2) {
        return this.VALUE_UNCHANGED;
      }
      if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
        return this.VALUE_UNCHANGED;
      }
      if (value1 === undefined) {
        return this.VALUE_CREATED;
      }
      if (value2 === undefined) {
        return this.VALUE_DELETED;
      }
      return this.VALUE_UPDATED;
    },
    isFunction: function (x) {
      return Object.prototype.toString.call(x) === '[object Function]';
    },
    isArray: function (x) {
      return Object.prototype.toString.call(x) === '[object Array]';
    },
    isDate: function (x) {
      return Object.prototype.toString.call(x) === '[object Date]';
    },
    isObject: function (x) {
      return Object.prototype.toString.call(x) === '[object Object]';
    },
    isValue: function (x) {
      return !this.isObject(x) && !this.isArray(x);
    }
  }
}();


var result = deepDiffMapper.map({
  a: 'i am unchanged',
  b: 'i am deleted',
  e: {
    a: 1,
    b: false,
    c: null
  },
  f: [1, {
    a: 'same',
    b: [{
      a: 'same'
    }, {
      d: 'delete'
    }]
  }],
  g: new Date('2017.11.25')
}, {
  a: 'i am unchanged',
  c: 'i am created',
  e: {
    a: '1',
    b: '',
    d: 'created'
  },
  f: [{
    a: 'same',
    b: [{
      a: 'same'
    }, {
      c: 'create'
    }]
  }, 1],
  g: new Date('2017.11.25')
});
console.log(result);


3
+1 এটি কোডের কোনও খারাপ অংশ নয়। তবুও একটি ত্রুটি রয়েছে (উদাহরণটি দেখুন: jsfiddle.net/kySNu/3 স্ট্রিং হওয়া উচিত cহিসাবে তৈরি করা হয়েছে ), এবং এটি ছাড়া আমার যা প্রয়োজন তা হয় না কারণ এটি গভীর অ্যারে মানের তুলনা করে যা এটি অত্যন্ত গুরুত্বপূর্ণ (এবং জটিল / জটিল) অংশ। পার্শ্ব নোট হিসাবে কনস্ট্রাক্টটি অকেজো কারণ অ্যারে এমন বস্তু যা অ্যারেগুলির উদাহরণ। undefined'i am created''array' != typeof(obj)
মার্টিন জেসপারসেন

1
আমি কোড আপডেট করেছি, তবে আমি নিশ্চিত নই যে আপনি ফলস্বরূপ অবজেক্টে কী মান চান, এখনই কোডটি প্রথম অবজেক্ট থেকে মান ফিরিয়ে দিচ্ছে এবং যদি এটির দ্বিতীয়টির থেকে মান না থাকে তবে ডেটা হিসাবে সেট করা হবে।
sbgoran

1
এবং আপনার অর্থ কীভাবে অ্যারেগুলির জন্য "গভীর অ্যারের মান তুলনা করা যায় না" আপনি প্রতিটি সূচি যেটিকে اعتراض করে তা পেতে পারেন {type: ..., data:..}। যেটি অনুপস্থিত তা হ'ল দ্বিতীয় অ্যারে থেকে মূল্য অনুসন্ধান করা, তবে আমি আমার উত্তরে উল্লেখ করেছি যে অ্যারেগুলি যদি তাদের মানগুলির ক্রম সমান না হয় ( [1, 2, 3] is not equal to [3, 2, 1]আমার মতে) সমান হয় না ।
sbgoran

6
@MartinJespersen ঠিক আছে, তুমি কেমন জেনেরিক এই অ্যারে তারপর চিকিত্সা হবে: [{key: 'value1'}] and [{key: 'value2'}, {key: 'value3'}]। প্রথম অ্যারেতে এখন প্রথম অবজেক্টটি "মান 1" বা "মান 2" দিয়ে আপডেট হয়েছে। এবং এটি সাধারণ উদাহরণ, এটি গভীর বাসা বাঁধার সাথে আরও জটিল হয়ে উঠতে পারে। আপনি যদি চান / বস্তুর অ্যারে তৈরি করবেন না, আগের উদাহরণস্বরূপ মত নেস্টেড বস্তুর সঙ্গে বস্তু তৈরি কী অবস্থান নির্বিশেষে গভীর পাখির তুলনা প্রয়োজন: {inner: {key: 'value1'}} and {inner: {key: 'value2'}, otherInner: {key: 'value3'}}
sbgoran

2
আমি আপনার সাথে শেষ দৃষ্টিকোণের সাথে একমত - মূল ডেটা কাঠামো এমন কিছুতে পরিবর্তন করা উচিত যা সত্যিকারের পার্থক্য করা সহজ। অভিনন্দন, আপনি পেরেক দিয়ে
মার্টিন জেসপারসেন

88

ইন্ডসকোর ব্যবহার করে, একটি সাধারণ পার্থক্য:

var o1 = {a: 1, b: 2, c: 2},
    o2 = {a: 2, b: 1, c: 2};

_.omit(o1, function(v,k) { return o2[k] === v; })

এর সাথে সম্পর্কিত অংশগুলিতে ফলাফল o1কিন্তু বিভিন্ন মান সহ o2:

{a: 1, b: 2}

একটি গভীর পার্থক্যের জন্য এটি আলাদা হতে চাই:

function diff(a,b) {
    var r = {};
    _.each(a, function(v,k) {
        if(b[k] === v) return;
        // but what if it returns an empty object? still attach?
        r[k] = _.isObject(v)
                ? _.diff(v, b[k])
                : v
            ;
        });
    return r;
}

মন্তব্যগুলিতে @ জুহানা দ্বারা চিহ্নিত হিসাবে, উপরেরটি কেবল একটি পৃথক a -> খ এবং বিপরীত নয় (অর্থ বিতে অতিরিক্ত বৈশিষ্ট্য উপেক্ষা করা হবে)। পরিবর্তে এ -> বি -> এ ব্যবহার করুন:

(function(_) {
  function deepDiff(a, b, r) {
    _.each(a, function(v, k) {
      // already checked this or equal...
      if (r.hasOwnProperty(k) || b[k] === v) return;
      // but what if it returns an empty object? still attach?
      r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
    });
  }

  /* the function */
  _.mixin({
    diff: function(a, b) {
      var r = {};
      deepDiff(a, b, r);
      deepDiff(b, a, r);
      return r;
    }
  });
})(_.noConflict());

সম্পূর্ণ উদাহরণ + পরীক্ষা + মিশ্রণগুলির জন্য http://jsfiddle.net/drzaus/9g5qoxwj/ দেখুন


আপনি কেন নিম্নমানের হয়ে গেছেন তা নিশ্চিত নন, আপনি অগভীর, সাধারণ উদাহরণের পাশাপাশি আরও জটিল গভীর ফাংশন সরবরাহ করার কারণে এটি যথেষ্ট।
সেয়েরিয়া

2
@ সিয়েরিয়া ঘৃণা করবে বলে আমি ধারণা করি ... আমি উভয়ই করেছি কারণ আমি প্রাথমিকভাবে ভেবেছিলাম omitএটি একটি গভীর পার্থক্য, তবে ভুল ছিল, তাই তুলনার জন্যও অন্তর্ভুক্ত ছিল।
ড্রজাউস

1
সুন্দর সমাধান। আমি পরিবর্তন করতে সুপারিশ করবে r[k] = ... : vমধ্যে r[k] = ... : {'a':v, 'b':b[k] }এই ভাবে আপনি দুটি মানের দেখতে পারেন,।
গুয়ালনি

2
এই দুটিই মিথ্যা নেতিবাচক প্রত্যাবর্তন করে যখন বস্তু অন্যথায় অভিন্ন হয় তবে দ্বিতীয়টিতে আরও উপাদান থাকে, যেমন {a:1, b:2}এবং {a:1, b:2, c:3}
জেজেজে

1
এটি এর _.omitByপরিবর্তে হওয়া উচিত _.omit
জেপি

48

আমি একটি ES6 সমাধান অফার করতে চাই ... এটি একতরফা পার্থক্য, এর অর্থ এটি কীগুলি / মানগুলি o2যেগুলির প্রতিযোগীদের অনুরূপ নয় তার মধ্যে ফিরে আসবে o1:

let o1 = {
  one: 1,
  two: 2,
  three: 3
}

let o2 = {
  two: 2,
  three: 3,
  four: 4
}

let diff = Object.keys(o2).reduce((diff, key) => {
  if (o1[key] === o2[key]) return diff
  return {
    ...diff,
    [key]: o2[key]
  }
}, {})

3
খুব ভাল সমাধান তবে আপনি সেই if(o1[key] === o1[key])লাইন
ডুডটি

কোডটি কি সম্পূর্ণ? আমি পাচ্ছিUncaught SyntaxError: Unexpected token ...
Seano

2
আমি সমাধানটি পছন্দ করি তবে এটির একটি সমস্যা রয়েছে, যদি বিষয়টি এক স্তরের চেয়ে গভীর হয়, তবে এটি পরিবর্তিত নেস্টেড বস্তুর সমস্ত মান ফিরিয়ে দেবে - বা কমপক্ষে এটি আমার জন্য যা ঘটছে।
সুস্পষ্ট

3
হ্যাঁ, এটি পুনরুত্থিত নয় @ জালিয়াতিপূর্ণ
নিমেসারিয়াল

2
শুধু মনে রাখবেন যে এই সমাধানের সাহায্যে, অবজেক্টের প্রতিটি উপাদানটির জন্য আপনি অ্যারেতে একটি আইটেম যুক্ত করতে এটিতে বিদ্যমান বিদ্যমান উপাদানগুলির সাথে অনুলিপি করা একটি সম্পূর্ণ নতুন অবজেক্ট পাবেন। ছোট বস্তুর জন্য এটি ঠিক আছে, তবে এটি বৃহত্তর অবজেক্টগুলির জন্য দ্রুত গতি কমিয়ে দেবে।
মালভাইনাস

22

লোডাশ ব্যবহার:

_.mergeWith(oldObj, newObj, function (objectValue, sourceValue, key, object, source) {
    if ( !(_.isEqual(objectValue, sourceValue)) && (Object(objectValue) !== objectValue)) {
        console.log(key + "\n    Expected: " + sourceValue + "\n    Actual: " + objectValue);
    }
});

আমি কী / অবজেক্ট / উত্স ব্যবহার করি না তবে আপনার যদি তাদের অ্যাক্সেসের প্রয়োজন হয় তবে আমি এটি সেখানে রেখে দিয়েছি। অবজেক্টের তুলনা কেবল কনসোলের বহিরাগত উপাদান থেকে আন্তঃতম উপাদানগুলিতে কনসোলের পার্থক্যগুলি মুদ্রণ করতে বাধা দেয়।

অ্যারেগুলি পরিচালনা করতে আপনি কিছু যুক্তি যুক্ত করতে পারেন। প্রথমে অ্যারেগুলি বাছাই করুন। এটি একটি খুব নমনীয় সমাধান।

সম্পাদনা

লড্যাশ আপডেটের কারণে _ ডুবে _ _ ডুবে গেছে। ধন্যবাদ পরিবর্তনটি লক্ষ্য করার জন্য পরিবেশ।


6
লোডাসে ৪.১৫.০ এ _ কাস্টমাইজার ফাংশন সহ ডুবে থাকা এখন আর সমর্থিত নয় সুতরাং এর পরিবর্তে আপনার _ ডাবল ব্যবহার করা উচিত।
আভিরান কোহেন

1
এই ফাংশনটি দুর্দান্ত তবে নেস্টেড অবজেক্টে কাজ করছে না।
জো অ্যালেন

13

এখানে একটি জাভাস্ক্রিপ্ট লাইব্রেরি যা আপনি দুটি জাভাস্ক্রিপ্ট অবজেক্টের মধ্যে পার্থক্য সন্ধানের জন্য ব্যবহার করতে পারেন:

গিথুব ইউআরএল: https://github.com/cosmicanant/recursive-diff

এনপিএমজেস ইউআরএল: https://www.npmjs.com/package/recursive-diff

আপনি ব্রাউজারে নোড.জেএস-তে পুনরাবৃত্ত-ডিফ লাইব্রেরি ব্যবহার করতে পারেন। ব্রাউজারের জন্য, নিম্নলিখিতগুলি করুন:

<script type="text" src="https://unpkg.com/recursive-diff@1.0.0/dist/recursive-diff.min.js"/>
<script type="text/javascript">
     const ob1 = {a:1, b: [2,3]};
     const ob2 = {a:2, b: [3,3,1]};
     const delta = recursiveDiff.getDiff(ob1,ob2); 
     /* console.log(delta) will dump following data 
     [
         {path: ['a'], op: 'update', val: 2}
         {path: ['b', '0'], op: 'update',val: 3},
         {path: ['b',2], op: 'add', val: 1 },
     ]
      */
     const ob3 = recursiveDiff.applyDiff(ob1, delta); //expect ob3 is deep equal to ob2
 </script>

যদিও নোড.জেজে আপনি 'রিকার্সভেফ-ডিফ' মডিউলটি প্রয়োজন এবং এটি নীচের মতো ব্যবহার করতে পারেন:

const diff = require('recursive-diff');
const ob1 = {a: 1}, ob2: {b:2};
const diff = diff.getDiff(ob1, ob2);

উদাহরণস্বরূপ, এটি তারিখের বৈশিষ্ট্যগুলির পরিবর্তনের জন্য অ্যাকাউন্ট করবে না।
ট্রোলকোটজে

তারিখ সমর্থন যোগ করা হয়েছে
অনন্ত

9

আজকাল, এই জন্য বেশ কয়েকটি মডিউল উপলব্ধ। আমি সম্প্রতি এটি করার জন্য একটি মডিউল লিখেছি কারণ আমি যে অসংখ্য বিচিত্র মডিউল পেয়েছি তাতে সন্তুষ্ট নই। এটি বলে odiff: https://github.com/Tixit/odiff । আমি সর্বাধিক জনপ্রিয় মডিউলগুলির একটি গুচ্ছ তালিকাভুক্ত করেছি এবং কেন সেগুলি রেডমিমে গ্রহণযোগ্য নয় odiff, যা odiffআপনি চান এমন বৈশিষ্ট্য না থাকলে আপনি একবার দেখে নিতে পারেন। এখানে একটি উদাহরণ:

var a = [{a:1,b:2,c:3},              {x:1,y: 2, z:3},              {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]

var diffs = odiff(a,b)

/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
 {type: 'set', path:[1,'y'], val: '3'},
 {type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/

7
const diff = require("deep-object-diff").diff;
let differences = diff(obj2, obj1);

500k এরও বেশি সাপ্তাহিক ডাউনলোড সহ একটি এনএমপি মডিউল রয়েছে: https://www.npmjs.com/package/DP-object-diff

পার্থক্যগুলির প্রতিনিধিত্ব করার মতো বিষয়টিকে আমি পছন্দ করি - বিশেষত কাঠামোটি তৈরি করা হলে কাঠামোটি দেখা সহজ।

const diff = require("deep-object-diff").diff;

const lhs = {
  foo: {
    bar: {
      a: ['a', 'b'],
      b: 2,
      c: ['x', 'y'],
      e: 100 // deleted
    }
  },
  buzz: 'world'
};

const rhs = {
  foo: {
    bar: {
      a: ['a'], // index 1 ('b')  deleted
      b: 2, // unchanged
      c: ['x', 'y', 'z'], // 'z' added
      d: 'Hello, world!' // added
    }
  },
  buzz: 'fizz' // updated
};

console.log(diff(lhs, rhs)); // =>
/*
{
  foo: {
    bar: {
      a: {
        '1': undefined
      },
      c: {
        '2': 'z'
      },
      d: 'Hello, world!',
      e: undefined
    }
  },
  buzz: 'fizz'
}
*/

2

আপনি যে টাস্কটি বর্ণনা করেছেন তা করার জন্য আমি এই কোডের টুকরোটি ব্যবহার করেছি:

function mergeRecursive(obj1, obj2) {
    for (var p in obj2) {
        try {
            if(obj2[p].constructor == Object) {
                obj1[p] = mergeRecursive(obj1[p], obj2[p]);
            }
            // Property in destination object set; update its value.
            else if (Ext.isArray(obj2[p])) {
                // obj1[p] = [];
                if (obj2[p].length < 1) {
                    obj1[p] = obj2[p];
                }
                else {
                    obj1[p] = mergeRecursive(obj1[p], obj2[p]);
                }

            }else{
                obj1[p] = obj2[p];
            }
        } catch (e) {
            // Property in destination object not set; create it and set its value.
            obj1[p] = obj2[p];
        }
    }
    return obj1;
}

এটি আপনাকে একটি নতুন অবজেক্ট দেবে যা পুরানো অবজেক্ট এবং নতুন ফর্মের মধ্যে সমস্ত রূপকে আপনার ফর্ম থেকে একীভূত করবে


1
আমি এখানে এক্সট্রাট ফ্রেমওয়ার্ক ব্যবহার করছি তবে আপনি এটি প্রতিস্থাপন করতে পারেন এবং আপনি যে কোনও ফ্রেমওয়ার্ক চান তা ব্যবহার করতে পারেন ...
এএমবার

মার্জ করা অবজেক্টগুলি তুচ্ছ এবং $.extend(true,obj1,obj2)jQuery ব্যবহার করার মতো সহজ করা যায় । এটি আমার যা প্রয়োজন তা মোটেই নয়। আমার দুটি বস্তুর মধ্যে পার্থক্য প্রয়োজন তাদের সংমিশ্রণ নয়।
মার্টিন জেসপারসেন

এটি দুর্দান্ত যে এক্সট এখানে ব্যবহৃত হয়
পেরোক্সাইড

2

আমি জাভাস্ক্রিপ্টে "তুলনাভালিউ ()" নামে ফাংশনটি তৈরি করেছি। এটি মানটি একই কিনা তা ফেরত দেয়। আমি একটি অবজেক্টের লুপের জন্য তুলনাভ্যালু () কল করেছি। আপনি ডিফারপ্যারামে দুটি বস্তুর পার্থক্য পেতে পারেন।

var diffParams = {};
var obj1 = {"a":"1", "b":"2", "c":[{"key":"3"}]},
    obj2 = {"a":"1", "b":"66", "c":[{"key":"55"}]};

for( var p in obj1 ){
  if ( !compareValue(obj1[p], obj2[p]) ){
    diffParams[p] = obj1[p];
  }
}

function compareValue(val1, val2){
  var isSame = true;
  for ( var p in val1 ) {

    if (typeof(val1[p]) === "object"){
      var objectValue1 = val1[p],
          objectValue2 = val2[p];
      for( var value in objectValue1 ){
        isSame = compareValue(objectValue1[value], objectValue2[value]);
        if( isSame === false ){
          return false;
        }
      }
    }else{
      if(val1 !== val2){
        isSame = false;
      }
    }
  }
  return isSame;
}
console.log(diffParams);


1

আমি জানি আমি পার্টিতে দেরি করেছি, তবে আমার অনুরূপ কিছু দরকার ছিল যা উপরের উত্তরগুলি সাহায্য করে না।

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

এই কোডটি এখানে: https://jsfiddle.net/rv01x6jo/

এটি কীভাবে ব্যবহার করবেন তা এখানে:

// To only return the difference
var difference = diff(newValue, oldValue);  

// To exclude certain properties
var difference = diff(newValue, oldValue, [newValue.prop1, newValue.prop2, newValue.prop3]);

আশা করি এটি কাউকে সাহায্য করবে।


দয়া করে আপনার উত্তরে কোডটি অন্তর্ভুক্ত করুন, কেবলমাত্র একটি বেড়াল নয়।
xpy

দেখে মনে হচ্ছে DefineProperty আরও ভাল পারফরম্যান্সের মাধ্যমে এই সমস্যাটি সমাধান করবে, যদি আমি সঠিকভাবে মনে করি এটি আই 9 এর সমস্ত পথে কাজ করে।
পিটার

ধন্যবাদ .. !! আপনার কোড মোহন মত কাজ করে এবং আমার দিন সংরক্ষণ। আমার কাছে 1250 লাইনের জেসন অবজেক্ট রয়েছে এবং এটি আমাকে সঠিক ও / পি দেয় যা আমি চাই।
তেজাস মেহতা

1

আমি কেবল রামদা ব্যবহার করি, একই সমস্যাটি সমাধান করার জন্য, আমার নতুন অবজেক্টে কী পরিবর্তন হয়েছে তা জানতে হবে। সুতরাং এখানে আমার নকশা।

const oldState = {id:'170',name:'Ivab',secondName:'Ivanov',weight:45};
const newState = {id:'170',name:'Ivanko',secondName:'Ivanov',age:29};

const keysObj1 = R.keys(newState)

const filterFunc = key => {
  const value = R.eqProps(key,oldState,newState)
  return {[key]:value}
}

const result = R.map(filterFunc, keysObj1)

ফলস্বরূপ, সম্পত্তির নাম এবং এটির স্থিতি।

[{"id":true}, {"name":false}, {"secondName":true}, {"age":false}]

1

এখানে @sbgoran কোডের একটি টাইপ স্ক্রিপ্ট সংস্করণ

export class deepDiffMapper {

  static VALUE_CREATED = 'created';
  static VALUE_UPDATED = 'updated';
  static VALUE_DELETED = 'deleted';
  static VALUE_UNCHANGED ='unchanged';

  protected isFunction(obj: object) {
    return {}.toString.apply(obj) === '[object Function]';
  };

  protected isArray(obj: object) {
      return {}.toString.apply(obj) === '[object Array]';
  };

  protected isObject(obj: object) {
      return {}.toString.apply(obj) === '[object Object]';
  };

  protected isDate(obj: object) {
      return {}.toString.apply(obj) === '[object Date]';
  };

  protected isValue(obj: object) {
      return !this.isObject(obj) && !this.isArray(obj);
  };

  protected compareValues (value1: any, value2: any) {
    if (value1 === value2) {
        return deepDiffMapper.VALUE_UNCHANGED;
    }
    if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
        return deepDiffMapper.VALUE_UNCHANGED;
    }
    if ('undefined' == typeof(value1)) {
        return deepDiffMapper.VALUE_CREATED;
    }
    if ('undefined' == typeof(value2)) {
        return deepDiffMapper.VALUE_DELETED;
    }

    return deepDiffMapper.VALUE_UPDATED;
  }

  public map(obj1: object, obj2: object) {
      if (this.isFunction(obj1) || this.isFunction(obj2)) {
          throw 'Invalid argument. Function given, object expected.';
      }
      if (this.isValue(obj1) || this.isValue(obj2)) {
          return {
              type: this.compareValues(obj1, obj2),
              data: (obj1 === undefined) ? obj2 : obj1
          };
      }

      var diff = {};
      for (var key in obj1) {
          if (this.isFunction(obj1[key])) {
              continue;
          }

          var value2 = undefined;
          if ('undefined' != typeof(obj2[key])) {
              value2 = obj2[key];
          }

          diff[key] = this.map(obj1[key], value2);
      }
      for (var key in obj2) {
          if (this.isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
              continue;
          }

          diff[key] = this.map(undefined, obj2[key]);
      }

      return diff;

  }
}

1

এখানে জিস্টহাবের কোনও কিছুর পরিবর্তিত সংস্করণ রয়েছে ।

isNullBlankOrUndefined = function (o) {
    return (typeof o === "undefined" || o == null || o === "");
}

/**
 * Deep diff between two object, using lodash
 * @param  {Object} object Object compared
 * @param  {Object} base   Object to compare with
 * @param  {Object} ignoreBlanks will not include properties whose value is null, undefined, etc.
 * @return {Object}        Return a new object who represent the diff
 */
objectDifference = function (object, base, ignoreBlanks = false) {
    if (!lodash.isObject(object) || lodash.isDate(object)) return object            // special case dates
    return lodash.transform(object, (result, value, key) => {
        if (!lodash.isEqual(value, base[key])) {
            if (ignoreBlanks && du.isNullBlankOrUndefined(value) && isNullBlankOrUndefined( base[key])) return;
            result[key] = lodash.isObject(value) && lodash.isObject(base[key]) ? objectDifference(value, base[key]) : value;
        }
    });
}

1

আমি @ sbgoran এর উত্তরটি পরিবর্তন করেছি যাতে ফলাফলের ডিফ অবজেক্টে কেবল পরিবর্তিত মান অন্তর্ভুক্ত থাকে এবং একই মানগুলিকে বাদ দেয়। এছাড়াও, এটি মূল মান এবং আপডেট হওয়া মান উভয়ই দেখায় ।

var deepDiffMapper = function () {
    return {
        VALUE_CREATED: 'created',
        VALUE_UPDATED: 'updated',
        VALUE_DELETED: 'deleted',
        VALUE_UNCHANGED: '---',
        map: function (obj1, obj2) {
            if (this.isFunction(obj1) || this.isFunction(obj2)) {
                throw 'Invalid argument. Function given, object expected.';
            }
            if (this.isValue(obj1) || this.isValue(obj2)) {
                let returnObj = {
                    type: this.compareValues(obj1, obj2),
                    original: obj1,
                    updated: obj2,
                };
                if (returnObj.type != this.VALUE_UNCHANGED) {
                    return returnObj;
                }
                return undefined;
            }

            var diff = {};
            let foundKeys = {};
            for (var key in obj1) {
                if (this.isFunction(obj1[key])) {
                    continue;
                }

                var value2 = undefined;
                if (obj2[key] !== undefined) {
                    value2 = obj2[key];
                }

                let mapValue = this.map(obj1[key], value2);
                foundKeys[key] = true;
                if (mapValue) {
                    diff[key] = mapValue;
                }
            }
            for (var key in obj2) {
                if (this.isFunction(obj2[key]) || foundKeys[key] !== undefined) {
                    continue;
                }

                let mapValue = this.map(undefined, obj2[key]);
                if (mapValue) {
                    diff[key] = mapValue;
                }
            }

            //2020-06-13: object length code copied from https://stackoverflow.com/a/13190981/2336212
            if (Object.keys(diff).length > 0) {
                return diff;
            }
            return undefined;
        },
        compareValues: function (value1, value2) {
            if (value1 === value2) {
                return this.VALUE_UNCHANGED;
            }
            if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
                return this.VALUE_UNCHANGED;
            }
            if (value1 === undefined) {
                return this.VALUE_CREATED;
            }
            if (value2 === undefined) {
                return this.VALUE_DELETED;
            }
            return this.VALUE_UPDATED;
        },
        isFunction: function (x) {
            return Object.prototype.toString.call(x) === '[object Function]';
        },
        isArray: function (x) {
            return Object.prototype.toString.call(x) === '[object Array]';
        },
        isDate: function (x) {
            return Object.prototype.toString.call(x) === '[object Date]';
        },
        isObject: function (x) {
            return Object.prototype.toString.call(x) === '[object Object]';
        },
        isValue: function (x) {
            return !this.isObject(x) && !this.isArray(x);
        }
    }
}();

0

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

আইই 8 তে 100% কাজ করে। সফলভাবে পরীক্ষিত।

//  ObjectKey: ["DataType, DefaultValue"]
reference = { 
    a : ["string", 'Defaul value for "a"'],
    b : ["number", 300],
    c : ["boolean", true],
    d : {
        da : ["boolean", true],
        db : ["string", 'Defaul value for "db"'],
        dc : {
            dca : ["number", 200],
            dcb : ["string", 'Default value for "dcb"'],
            dcc : ["number", 500],
            dcd : ["boolean", true]
      },
      dce : ["string", 'Default value for "dce"'],
    },
    e : ["number", 200],
    f : ["boolean", 0],
    g : ["", 'This is an internal extra parameter']
};

userOptions = { 
    a : 999, //Only string allowed
  //b : ["number", 400], //User missed this parameter
    c: "Hi", //Only lower case or case insitive in quotes true/false allowed.
    d : {
        da : false,
        db : "HelloWorld",
        dc : {
            dca : 10,
            dcb : "My String", //Space is not allowed for ID attr
            dcc: "3thString", //Should not start with numbers
            dcd : false
      },
      dce: "ANOTHER STRING",
    },
    e: 40,
    f: true,
};


function compare(ref, obj) {

    var validation = {
        number: function (defaultValue, userValue) {
          if(/^[0-9]+$/.test(userValue))
            return userValue;
          else return defaultValue;
        },
        string: function (defaultValue, userValue) {
          if(/^[a-z][a-z0-9-_.:]{1,51}[^-_.:]$/i.test(userValue)) //This Regex is validating HTML tag "ID" attributes
            return userValue;
          else return defaultValue;
        },
        boolean: function (defaultValue, userValue) {
          if (typeof userValue === 'boolean')
            return userValue;
          else return defaultValue;
        }
    };

    for (var key in ref)
        if (obj[key] && obj[key].constructor && obj[key].constructor === Object)
          ref[key] = compare(ref[key], obj[key]);
        else if(obj.hasOwnProperty(key))
          ref[key] = validation[ref[key][0]](ref[key][1], obj[key]); //or without validation on user enties => ref[key] = obj[key]
        else ref[key] = ref[key][1];
    return ref;
}

//console.log(
    alert(JSON.stringify( compare(reference, userOptions),null,2 ))
//);

/* ফলাফল

{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 10,
      "dcb": "Default value for \"dcb\"",
      "dcc": 500,
      "dcd": false
    },
    "dce": "Default value for \"dce\""
  },
  "e": 40,
  "f": true,
  "g": "This is an internal extra parameter"
}

*/

0

Sbgoran এর উত্তর থেকে আরও বর্ধিত এবং সরলকরণ ফাংশন।
এটি গভীর স্ক্যান করতে দেয় এবং অ্যারের সিমিলারিটি খুঁজে পেতে পারে।

var result = objectDifference({
      a:'i am unchanged',
      b:'i am deleted',
      e: {a: 1,b:false, c: null},
      f: [1,{a: 'same',b:[{a:'same'},{d: 'delete'}]}],
      g: new Date('2017.11.25'),
      h: [1,2,3,4,5]
  },
  {
      a:'i am unchanged',
      c:'i am created',
      e: {a: '1', b: '', d:'created'},
      f: [{a: 'same',b:[{a:'same'},{c: 'create'}]},1],
      g: new Date('2017.11.25'),
      h: [4,5,6,7,8]
  });
console.log(result);

function objectDifference(obj1, obj2){
    if((dataType(obj1) !== 'array' && dataType(obj1) !== 'object') || (dataType(obj2) !== 'array' && dataType(obj2) !== 'object')){
        var type = '';

        if(obj1 === obj2 || (dataType(obj1) === 'date' && dataType(obj2) === 'date' && obj1.getTime() === obj2.getTime()))
            type = 'unchanged';
        else if(dataType(obj1) === 'undefined')
            type = 'created';
        if(dataType(obj2) === 'undefined')
            type = 'deleted';
        else if(type === '') type = 'updated';

        return {
            type: type,
            data:(obj1 === undefined) ? obj2 : obj1
        };
    }
  
    if(dataType(obj1) === 'array' && dataType(obj2) === 'array'){
        var diff = [];
        obj1.sort(); obj2.sort();
        for(var i = 0; i < obj2.length; i++){
            var type = obj1.indexOf(obj2[i]) === -1?'created':'unchanged';
            if(type === 'created' && (dataType(obj2[i]) === 'array' || dataType(obj2[i]) === 'object')){
                diff.push(
                    objectDifference(obj1[i], obj2[i])
                );
                continue;
            }
            diff.push({
                type: type,
                data: obj2[i]
            });
        }

        for(var i = 0; i < obj1.length; i++){
            if(obj2.indexOf(obj1[i]) !== -1 || dataType(obj1[i]) === 'array' || dataType(obj1[i]) === 'object')
                continue;
            diff.push({
                type: 'deleted',
                data: obj1[i]
            });
        }
    } else {
        var diff = {};
        var key = Object.keys(obj1);
        for(var i = 0; i < key.length; i++){
            var value2 = undefined;
            if(dataType(obj2[key[i]]) !== 'undefined')
                value2 = obj2[key[i]];

            diff[key[i]] = objectDifference(obj1[key[i]], value2);
        }

        var key = Object.keys(obj2);
        for(var i = 0; i < key.length; i++){
            if(dataType(diff[key[i]]) !== 'undefined')
                continue;

            diff[key[i]] = objectDifference(undefined, obj2[key[i]]);
        }
    }

    return diff;
}

function dataType(data){
    if(data === undefined || data === null) return 'undefined';
    if(data.constructor === String) return 'string';
    if(data.constructor === Array) return 'array';
    if(data.constructor === Object) return 'object';
    if(data.constructor === Number) return 'number';
    if(data.constructor === Boolean) return 'boolean';
    if(data.constructor === Function) return 'function';
    if(data.constructor === Date) return 'date';
    if(data.constructor === RegExp) return 'regex';
    return 'unknown';
}


0

আমি দুটি পদার্থের মধ্যে পার্থক্য পেতে একটি উপায় সন্ধান করার চেষ্টা করে এখানে হোঁচট খেয়েছি। লোডাশ ব্যবহার করে এটি আমার সমাধান:

// Get updated values (including new values)
var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value));

// Get updated values (excluding new values)
var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value)));

// Get old values (by using updated values)
var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {});

// Get newly added values
var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key));

// Get removed values
var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key));

// Then you can group them however you want with the result

নীচে কোড স্নিপেট:

var last = {
"authed": true,
"inForeground": true,
"goodConnection": false,
"inExecutionMode": false,
"online": true,
"array": [1, 2, 3],
"deep": {
	"nested": "value",
},
"removed": "value",
};

var curr = {
"authed": true,
"inForeground": true,
"deep": {
	"nested": "changed",
},
"array": [1, 2, 4],
"goodConnection": true,
"inExecutionMode": false,
"online": false,
"new": "value"
};

// Get updated values (including new values)
var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value));
// Get updated values (excluding new values)
var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value)));
// Get old values (by using updated values)
var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {});
// Get newly added values
var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key));
// Get removed values
var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key));

console.log('oldValues', JSON.stringify(oldValues));
console.log('updatedValuesIncl', JSON.stringify(updatedValuesIncl));
console.log('updatedValuesExcl', JSON.stringify(updatedValuesExcl));
console.log('newCreatedValues', JSON.stringify(newCreatedValues));
console.log('deletedValues', JSON.stringify(deletedValues));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>


0

আমি উপরে @sbgoran দ্বারা উত্তরটি নিয়েছি এবং এটি আমার প্রশ্নের প্রয়োজন মত প্রশ্নের জন্য একইভাবে সংশোধন করেছি, অ্যারেগুলিকে সেট হিসাবে বিবেচনা করুন (অর্থাত্ আদেশটি ডিফারের জন্য গুরুত্বপূর্ণ নয়)

const deepDiffMapper = function () {
return {
  VALUE_CREATED: "created",
  VALUE_UPDATED: "updated",
  VALUE_DELETED: "deleted",
  VALUE_UNCHANGED: "unchanged",
  map: function(obj1: any, obj2: any) {
    if (this.isFunction(obj1) || this.isFunction(obj2)) {
      throw "Invalid argument. Function given, object expected.";
    }
    if (this.isValue(obj1) || this.isValue(obj2)) {
      return {
        type: this.compareValues(obj1, obj2),
        data: obj2 === undefined ? obj1 : obj2
      };
    }

    if (this.isArray(obj1) || this.isArray(obj2)) {
      return {
        type: this.compareArrays(obj1, obj2),
        data: this.getArrayDiffData(obj1, obj2)
      };
    }

    const diff: any = {};
    for (const key in obj1) {

      if (this.isFunction(obj1[key])) {
        continue;
      }

      let value2 = undefined;
      if (obj2[key] !== undefined) {
        value2 = obj2[key];
      }

      diff[key] = this.map(obj1[key], value2);
    }
    for (const key in obj2) {
      if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
        continue;
      }

      diff[key] = this.map(undefined, obj2[key]);
    }

    return diff;

  },

  getArrayDiffData: function(arr1: Array<any>, arr2: Array<any>) {
    const set1 = new Set(arr1);
    const set2 = new Set(arr2);

    if (arr1 === undefined || arr2 === undefined) {
       return arr1 === undefined ? arr1 : arr2;
    }
    const deleted = [...arr1].filter(x => !set2.has(x));

    const added = [...arr2].filter(x => !set1.has(x));

    return {
      added, deleted
    };

  },

  compareArrays: function(arr1: Array<any>, arr2: Array<any>) {
    const set1 = new Set(arr1);
    const set2 = new Set(arr2);
    if (_.isEqual(_.sortBy(arr1), _.sortBy(arr2))) {
      return this.VALUE_UNCHANGED;
    }
    if (arr1 === undefined) {
      return this.VALUE_CREATED;
    }
    if (arr2 === undefined) {
      return this.VALUE_DELETED;
    }
    return this.VALUE_UPDATED;
  },
  compareValues: function (value1: any, value2: any) {
    if (value1 === value2) {
      return this.VALUE_UNCHANGED;
    }
    if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
      return this.VALUE_UNCHANGED;
    }
    if (value1 === undefined) {
      return this.VALUE_CREATED;
    }
    if (value2 === undefined) {
      return this.VALUE_DELETED;
    }
    return this.VALUE_UPDATED;
  },
  isFunction: function (x: any) {
    return Object.prototype.toString.call(x) === "[object Function]";
  },
  isArray: function (x: any) {
    return Object.prototype.toString.call(x) === "[object Array]";
  },
  isDate: function (x: any) {
    return Object.prototype.toString.call(x) === "[object Date]";
  },
  isObject: function (x: any) {
    return Object.prototype.toString.call(x) === "[object Object]";
  },
  isValue: function (x: any) {
    return !this.isObject(x) && !this.isArray(x);
  }
 };
}();

0

এখানে একটি সমাধান যা:

  • প্রকারের স্ক্রিপ্ট (তবে জাভাস্ক্রিপ্টে সহজে রূপান্তরযোগ্য)
  • কোন lib নির্ভরতা আছে
  • জেনেরিক এবং অবজেক্টের ধরণগুলি পরীক্ষা করার বিষয়ে চিন্তা করে না (প্রকারের পাশে object)
  • মান সহ বৈশিষ্ট্য সমর্থন করে undefined
  • গভীর না (ডিফল্ট)

প্রথমে আমরা তুলনা ফলাফল ইন্টারফেস সংজ্ঞায়িত:

export interface ObjectComparison {
  added: {};
  updated: {
    [propName: string]: Change;
  };
  removed: {};
  unchanged: {};
}

পরিবর্তনের বিশেষ ক্ষেত্রে যেখানে আমরা জানতে চাই যে পুরানো এবং নতুন মানগুলি কী:

export interface Change {
  oldValue: any;
  newValue: any;
}

তারপরে আমরা diffফাংশনটি সরবরাহ করতে পারি যা কেবল দুটি লুপ (যদি পুনরাবৃত্তির সাথে থাকে deepতবে true):

export class ObjectUtils {

  static diff(o1: {}, o2: {}, deep = false): ObjectComparison {
    const added = {};
    const updated = {};
    const removed = {};
    const unchanged = {};
    for (const prop in o1) {
      if (o1.hasOwnProperty(prop)) {
        const o2PropValue = o2[prop];
        const o1PropValue = o1[prop];
        if (o2.hasOwnProperty(prop)) {
          if (o2PropValue === o1PropValue) {
            unchanged[prop] = o1PropValue;
          } else {
            updated[prop] = deep && this.isObject(o1PropValue) && this.isObject(o2PropValue) ? this.diff(o1PropValue, o2PropValue, deep) : {newValue: o2PropValue};
          }
        } else {
          removed[prop] = o1PropValue;
        }
      }
    }
    for (const prop in o2) {
      if (o2.hasOwnProperty(prop)) {
        const o1PropValue = o1[prop];
        const o2PropValue = o2[prop];
        if (o1.hasOwnProperty(prop)) {
          if (o1PropValue !== o2PropValue) {
            if (!deep || !this.isObject(o1PropValue)) {
              updated[prop].oldValue = o1PropValue;
            }
          }
        } else {
          added[prop] = o2PropValue;
        }
      }
    }
    return { added, updated, removed, unchanged };
  }

  /**
   * @return if obj is an Object, including an Array.
   */
  static isObject(obj: any) {
    return obj !== null && typeof obj === 'object';
  }
}

উদাহরণ হিসাবে, কল করা:

ObjectUtils.diff(
  {
    a: 'a', 
    b: 'b', 
    c: 'c', 
    arr: ['A', 'B'], 
    obj: {p1: 'p1', p2: 'p2'}
  },
  {
    b: 'x', 
    c: 'c', 
    arr: ['B', 'C'], 
    obj: {p2: 'p2', p3: 'p3'}, 
    d: 'd'
  },
);

ফিরে আসবে:

{
  added: {d: 'd'},
  updated: {
    b: {oldValue: 'b', newValue: 'x'},
    arr: {oldValue: ['A', 'B'], newValue: ['B', 'C']},
    obj: {oldValue: {p1: 'p1', p2: 'p2'}, newValue: {p2: 'p2', p3: 'p3'}}
  },
  removed: {a: 'a'},
  unchanged: {c: 'c'},
}

এবং deepতৃতীয় প্যারামিটার দিয়ে একই কল করা ফিরে আসবে:

{
  added: {d: 'd'},
  updated: {
    b: {oldValue: 'b', newValue: 'x'},
    arr: {
      added: {},
      removed: {},
      unchanged: {},
      updated: {
        0: {oldValue: 'A', newValue: 'B'},
        1: {oldValue: 'B', newValue: 'C', }
      }
    },
    obj: {
      added: {p3: 'p3'},
      removed: {p1: 'p1'},
      unchanged: {p2: 'p2'},
      updated: {}
    }
  },
  removed: {a: 'a'},
  unchanged: {c: 'c'},
}

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