javascript - سكربت - شرح جافا سكريبت




كيفية دمج صفيفين في عناصر جافا سكريبت وإزالة التكرار (20)

ES6

array1.push(...array2) // => don't remove duplication 

أو

[...array1,...array2] //   =>  don't remove duplication 

أو

[...new Set([...array1 ,...array2])]; //   => remove duplication

لدي صفحتان JavaScript:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

أريد أن يكون الإخراج:

var array3 = ["Vijendra","Singh","Shakya"];

يجب أن يكون لديك مجموعة الإخراج إزالة الكلمات المتكررة.

كيف أقوم بدمج مصفوفين في JavaScript حتى أحصل على العناصر الفريدة من كل صفيف بنفس الترتيب الذي تم إدخالها به في المصفوفات الأصلية؟


نهج وظيفي مع ES2015

بعد النهج الوظيفي ، فإن union يتكون من صفحتين هو تركيبة concat و filter . من أجل توفير الأداء الأمثل ، نلجأ إلى نوع بيانات Set الأصلية ، والذي تم تحسينه لعمليات البحث عن العقارات.

على أي حال ، فإن السؤال الرئيسي بالتعاون مع وظيفة union هو كيفية التعامل مع التكرارات. التباديل التالي ممكن:

Array A      + Array B

[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

أول تباديل اثنين من السهل التعامل مع وظيفة واحدة. ومع ذلك ، فالآخران أكثر تعقيدًا ، نظرًا لأنك لا تستطيع معالجتها طالما أنك تعتمد على عمليات Set . نظرًا لأن التبديل إلى عمليات البحث عن خاصية Object قديم عادي سيستلزم أداءً خطيرًا ، فإن التنفيذ التالي يتجاهل التقليب الثالث والرابع. سيكون عليك بناء نسخة منفصلة من union لدعمهم.

// small, reusable auxiliary functions

const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// de-duplication

const dedupe = comp(afrom) (createSet);


// the actual union function

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];


// here we go

console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );

من هنا ، يصبح من الصعب تنفيذ وظيفة unionn ، والتي تقبل أي عدد من المصفوفات (مستوحاة من تعليقات naomik):

// small, reusable auxiliary functions

const uncurry = f => (a, b) => f(a) (b);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// union and unionn

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}

const unionn = (head, ...tail) => foldl(union) (head) (tail);


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];


// here we go

console.log( unionn(xs, ys, zs) );

اتضح unionn هو مجرد foldl (ويعرف أيضا باسم Array.prototype.reduce ) ، الذي يأخذ union Array.prototype.reduce لها. ملاحظة: بما أن التنفيذ لا يستخدم تراكمًا إضافيًا ، فسيقوم بإلقاء خطأ عند تطبيقه بدون وسائط.


أفضل حل...

يمكنك التحقق مباشرة في وحدة تحكم المستعرض عن طريق الضغط على ...

بدون تكرار

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

مع مكررة

["prince", "asish", 5].concat(["ravi", 4])

إذا كنت تريد بدون تكرار يمكنك تجربة حل أفضل من هنا - Shouting Code .

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

جرب على وحدة تحكم المتصفح كروم

 f12 > console

انتاج:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

إذا افترضنا أن المصفوفات الأصلية لا تحتاج إلى نسخ من الازدواجية ، فيجب أن يكون ذلك سريعًا إلى حد ما ، مع الاحتفاظ بالترتيب الأصلي ، ولا يعدّل المصفوفات الأصلية ...

function arrayMerge(base, addendum){
    var out = [].concat(base);
    for(var i=0,len=addendum.length;i<len;i++){
        if(base.indexOf(addendum[i])<0){
            out.push(addendum[i]);
        }
    }
    return out;
}

الاستعمال:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = arrayMerge(array1, array2);

console.log(array3);
//-> [ 'Vijendra', 'Singh', 'Shakya' ]

باستخدام Set (ECMAScript 2015) ، سيكون الأمر بهذه البساطة:

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = Array.from(new Set(array1.concat(array2)));


تسلسل صفيفتين أولاً ، بعد ذلك تصفية العناصر الفريدة فقط.

var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b);
var d = c.filter(function (item, pos) {return c.indexOf(item) == pos});

// d is [1,2,3,101,10]

http://jsfiddle.net/simo/98622/

تصحيح

وفقًا لما اقترحهDmitry (راجع التعليق الثاني أدناه) ، سيكون الحل الأكثر حكمة من حيث الأداء هو تصفية العناصر الفريدة في b قبل التسلسل مع

var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b.filter(function (item) {
    return a.indexOf(item) < 0;
}));

// d is [1,2,3,101,10]

حل جديد (يستخدم Array.prototype.indexOf و Array.prototype.concat ):

Array.prototype.uniqueMerge = function( a ) {
    for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
        if ( this.indexOf( a[i] ) === -1 ) {
            nonDuplicates.push( a[i] );
        }
    }
    return this.concat( nonDuplicates )
};

الاستعمال:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

Array.prototype.indexOf (لـ internet explorer):

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

في دوجو 1.6+

var unique = []; 
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merged both arrays

dojo.forEach(array3, function(item) {
    if (dojo.indexOf(unique, item) > -1) return;
    unique.push(item); 
});

تحديث

انظر رمز العمل.

http://jsfiddle.net/UAxJa/1/


قم بدمج عدد غير محدود من المصفوفات أو غير المصفوفات وإبقائها فريدة من نوعها:

function flatMerge() {
    return Array.prototype.reduce.call(arguments, function (result, current) {
        if (!(current instanceof Array)) {
            if (result.indexOf(current) === -1) {
                result.push(current);
            }
        } else {
            current.forEach(function (value) {
                console.log(value);
                if (result.indexOf(value) === -1) {
                    result.push(value);
                }
            });
        }
        return result;
    }, []);
}

flatMerge([1,2,3], 4, 4, [3, 2, 1, 5], [7, 6, 8, 9], 5, [4], 2, [3, 2, 5]);
// [1, 2, 3, 4, 5, 7, 6, 8, 9]

flatMerge([1,2,3], [3, 2, 1, 5], [7, 6, 8, 9]);
// [1, 2, 3, 5, 7, 6, 8, 9]

flatMerge(1, 3, 5, 7);
// [1, 3, 5, 7]

لماذا لا تستخدم شيئًا؟ يبدو أنك تحاول تصميم مجموعة. هذا لن يحافظ على النظام ، ولكن.

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

مجرد رمي في بلدي سنتا.

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

هذه طريقة أستخدمها كثيرًا ، فهي تستخدم كائنًا كجدول hashlookup لإجراء التدقيق المكرر. بافتراض أن التجزئة هي O (1) ، فإن هذا يعمل في O (n) حيث n هو a.length + b.length. بصراحة ليس لدي أي فكرة عن كيفية عمل المتصفح للعلامة التجارية ، ولكنه يؤدي أداءً جيدًا في العديد من نقاط البيانات.


هنا هو اختلاف طفيف في الحلقة. من خلال بعض التحسينات التي تم إدخالها على أحدث إصدار من Chrome ، تعد هذه الطريقة هي الطريقة الأسرع لحل اتحاد الصفيفتين (Chrome 38.0.2111).

jsperf.com/merge-two-arrays-keeping-only-unique-values

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

أثناء التكرار: ~ 589k ops / s
مرشح: ~ 445k العمليات / ثانية
lodash: 308k ops / s
للحلقات: 225 كيلوبت / ثانية

أشار تعليق إلى أن أحد متغيرات الإعداد الخاصة بي كان يتسبب في قيام الحلقة بالانسحاب من الباقي ، لأنه لم يكن من الضروري تهيئة مصفوفة فارغة للكتابة عليها. أوافق على ذلك ، لذا قمت بإعادة كتابة الاختبار حتى في ميدان اللعب ، وقمت بتضمين خيار أسرع.

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/21

var whileLoopAlt = function(array1, array2) {
    var array3 = [];
    var arr = array1.concat(array2);
    var len = arr.length;
    var assoc = {};

    while(len--) {
        var itm = arr[len];

        if(!assoc[itm]) { // Eliminate the indexOf call
            array3.unshift(itm);
            assoc[itm] = true;
        }
    }

    return array3;
};

في هذا الحل البديل ، قمت بدمج حل صفيف .indexOf() واحد للإجابة لإزالة .indexOf() في الحلقة التي كانت تتباطأ الأشياء كثيرًا مع حلقة ثانية ، وتضمنت بعض التحسينات الأخرى التي اقترحها المستخدمون الآخرون في إجاباتهم كذلك.

لا تزال الإجابة الأعلى هنا مع الحلقة المزدوجة على كل قيمة (i-1) أبطأ بشكل ملحوظ. لا يزال لواش يعمل بقوة ، وما زلت أوصي به لأي شخص لا يمانع في إضافة مكتبة إلى مشروعه. بالنسبة لأولئك الذين لا يرغبون في ذلك ، لا يزال حلقي في حينه يمثل إجابة جيدة ، كما أن إجابة المرشح تحتوي على عرض قوي جدًا هنا ، وتغلب على جميع اختباراتي مع أحدث إصدار من Canary Chrome (44.0.2360) اعتبارًا من كتابة هذه السطور.

تحقق من إجابة مايك وجواب دان ستوكر إذا كنت ترغب في زيادة السرعة. هذه هي أسرع النتائج حتى الآن بعد المرور عبر جميع الإجابات القابلة للتطبيق.


يمكنك القيام بذلك ببساطة مع ECMAScript 6 ،

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • استخدم عامل انتشار لربط الصفيف.
  • استخدم Set لإنشاء مجموعة مميزة من العناصر.
  • مرة أخرى استخدم عامل انتشار لتحويل مجموعة في مصفوفة.

Another approach for your review with reduce func:

function mergeDistinct(arResult, candidate){
  if (-1 == arResult.indexOf(candidate)) {
    arResult.push(candidate);
  }
  return arResult;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var arMerge = [];
arMerge = array1.reduce(mergeDistinct, arMerge);
arMerge = array2.reduce(mergeDistinct, arMerge);//["Vijendra","Singh","Shakya"];

looks like the accepted answer is the slowest in my tests;

note I am merging 2 arrays of objects by Key

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button type='button' onclick='doit()'>do it</button>
<script>
function doit(){
    var items = [];
    var items2 = [];
    var itemskeys = {};
    for(var i = 0; i < 10000; i++){
        items.push({K:i, C:"123"});
        itemskeys[i] = i;
    }

    for(var i = 9000; i < 11000; i++){
        items2.push({K:i, C:"123"});
    }

    console.time('merge');
    var res = items.slice(0);

    //method1();
    method0();
    //method2();

    console.log(res.length);
    console.timeEnd('merge');

    function method0(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;
            if(itemskeys[k] == null){
                itemskeys[i] = res.length;
                res.push(items2[i]);
            }
        }
    }

    function method1(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;

            for(var j = 0; j < items.length; j++){
                if(items[j].K == k){
                    isok = 0;
                    break;
                }
            }

            if(isok) res.push(items2[i]);
        }  
    }

    function method2(){
        res = res.concat(items2);
        for(var i = 0; i < res.length; ++i) {
            for(var j = i+1; j < res.length; ++j) {
                if(res[i].K === res[j].K)
                    res.splice(j--, 1);
            }
        }
    }
}
</script>
</body>
</html>

إذا كنت تريد التحقق من وجود كائنات فريدة ، فاستخدم JSON.stringify في المقارنة.

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(JSON.stringify(a[i]) === JSON.stringify(a[j]))
                a.splice(j--, 1);
        }
    }

    return a;
}

//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

تنفيذ طريقة indexOf للمتصفحات الأخرى مأخوذة من MDC


Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

وهناك مجموعة دمج أفضل بكثير وظيفة.


Array.prototype.union = function (other_array) {
/* you can include a test to check whether other_array really is an array */
  other_array.forEach(function(v) { if(this.indexOf(v) === -1) {this.push(v);}}, this);    
}






merge