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




كيفية الحصول على قيم مميزة من مجموعة من الكائنات في JavaScript؟ (17)

underscore.js _.uniq(_.pluck(array,"age"))

على افتراض لدي ما يلي:

var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

ما هي أفضل طريقة لتكون قادرة على الحصول على مجموعة من جميع الأعمار المميزة بحيث أحصل على مجموعة نتائج:

[17, 35]

هل هناك طريقة يمكن بها ترتيب البيانات بطريقة بديلة أو طريقة أفضل بحيث لا أكون بحاجة إلى التكرار من خلال كل صف للتحقق من قيمة "العمر" والتحقق من صفيف آخر لوجودها ، وإضافتها إن لم يكن؟

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

الطريقة غير الفعالة الحالية أود تحسينها ... إذا كان ذلك يعني أنه بدلاً من أن تكون "المصفوفة" عبارة عن مصفوفة من الكائنات ، ولكن "خريطة" للكائنات ذات مفتاح فريد (أي "1 ، 2 ، 3") ، حسنا ايضا. ايم تبحث فقط عن الطريقة الأكثر كفاءة في الأداء.

ما يلي هو كيف أفعل ذلك في الوقت الحالي ، ولكن بالنسبة لي ، يبدو التكرار مخادعًا للكفاءة على الرغم من أنه يعمل ...

var distinct = []
for (var i = 0; i < array.length; i++)
   if (array[i].age not in distinct)
      distinct.push(array[i].age)

أعتقد أنك تبحث عن وظيفة groupBy (باستخدام Lodash)

_personsList = [{"name":"Joe", "age":17}, 
                {"name":"Bob", "age":17}, 
                {"name":"Carl", "age": 35}];
_uniqAgeList = _.groupBy(_personsList,"age");
_uniqAges = Object.keys(_uniqAgeList);

ينتج النتيجة:

17,35

jsFiddle demo: http://jsfiddle.net/4J2SX/201/


إذا كان لديك Array.prototype.includes أو كنت على استعداد لتعبئته ، فهذا يعمل:

var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });

إذا كانت هذه هي PHP ، فسوف أقوم بإنشاء مصفوفة مع المفاتيح وأخذ array_keys في النهاية ، ولكن JS ليس لديها مثل هذا الترف. بدلا من ذلك ، حاول هذا:

var flags = [], output = [], l = array.length, i;
for( i=0; i<l; i++) {
    if( flags[array[i].age]) continue;
    flags[array[i].age] = true;
    output.push(array[i].age);
}

إذا كنت مثلي تفضل أكثر "وظيفية" دون التضحية بالسرعة ، يستخدم هذا المثال بحث القاموس السريع الملفوف داخل تقليل الإغلاق.

var array = 
[
    {"name":"Joe", "age":17}, 
    {"name":"Bob", "age":17}, 
    {"name":"Carl", "age": 35}
]
var uniqueAges = array.reduce((p,c,i,a) => {
    if(!p[0][c.age]) {
        p[1].push(p[0][c.age] = c.age);
    }
    if(i<a.length-1) {
        return p
    } else {
        return p[1]
    }
}, [{},[]])

وفقًا لهذا test يكون حلّي أسرع بمرتين من الإجابة المقترحة


إليك طريقة أخرى لحل هذه المشكلة:

var result = {};
for(var i in array) {
    result[array[i].age] = null;
}
result = Object.keys(result);

ليس لدي أي فكرة عن مدى سرعة مقارنة هذا الحل مع الآخرين ، لكني أحب النظافة. ؛-)

تحرير: حسنا ، ما ورد أعلاه يبدو أن أبطأ الحل هنا.

لقد قمت بإنشاء حالة اختبار أداء هنا: http://jsperf.com/distinct-values-from-array

بدلاً من الاختبار للأعمار (الأعداد الصحيحة) ، اخترت مقارنة الأسماء (السلاسل).

الطريقة الأولى (حل TS) سريع جدًا. بشكل مثير للإهتمام ، تفوق الطريقة 7 على جميع الحلول الأخرى ، هنا أنا فقط تخلصت من .indexOf () واستخدمت تطبيقًا "يدويًا" ، متجنبة استدعاء دالة looped:

var result = [];
loop1: for (var i = 0; i < array.length; i++) {
    var name = array[i].name;
    for (var i2 = 0; i2 < result.length; i2++) {
        if (result[i2] == name) {
            continue loop1;
        }
    }
    result.push(name);
}

يعتبر الاختلاف في الأداء باستخدام Safari & Firefox أمرًا رائعًا ، ويبدو أن Chrome يحقق أفضل أداء في التحسين.

لست متأكدًا تمامًا من السبب في أن المقتطفات المذكورة أعلاه سريعة جدًا مقارنةً بالآخرين ، فربما يكون شخص أكثر حكمة منّي لديه إجابة. ؛-)


باستخدام d3.js v3 :

  ages = d3.set(
    array.map(function (d) { return d.age; })
  ).values();

باستخدام Lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];

_.chain(array).map('age').unique().value();

عوائد [17،35]


باستخدام ES6

let array = [
  { "name": "Joe", "age": 17 },
  { "name": "Bob", "age": 17 },
  { "name": "Carl", "age": 35 }
];
array.map(item => item.age)
  .filter((value, index, self) => self.indexOf(value) === index)

> [17, 35]

باستخدام ميزات ES6 ، يمكنك تنفيذ ما يلي:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];

حاول فقط

var x = [] ;
for (var i = 0 ; i < array.length ; i++)
{
 if(x.indexOf(array[i]['age']) == -1)
  {
    x.push(array[i]['age']);
  }
}
console.log(x);

فقط وجدت هذا واعتقدت أنه مفيد

_.map(_.indexBy(records, '_id'), function(obj){return obj})

مرة أخرى باستخدام underscore ، لذلك إذا كان لديك كائن مثل هذا

var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}]

سوف يعطيك الكائنات الفريدة فقط.

ما يحدث هنا هو أن indexBy بإرجاع خريطة مثل هذا

{ 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} }

ولأنها خريطة ، فكل المفاتيح فريدة.

ثم أنا مجرد تعيين هذه القائمة مرة أخرى إلى مجموعة.

في حال كنت بحاجة إلى القيم المميزة فقط

_.map(_.indexBy(records, '_id'), function(obj,key){return key})

ضع في اعتبارك أنه يتم إرجاع key كسلسلة ، لذلك ، إذا كنت بحاجة إلى الأعداد الصحيحة بدلاً من ذلك ، فعليك القيام بذلك

_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})

لقد بدأت التمسك Underscore في جميع المشاريع الجديدة افتراضيا فقط لذلك لم يكن لي أبدا أن نفكر في هذه المشاكل الصغيرة البيانات المعلقة.

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
console.log(_.chain(array).map(function(item) { return item.age }).uniq().value());

تنتج [17, 35] .


هذه الوظيفة يمكن أن مجموعة فريدة وجوه

function oaunic(x,n=0){
    if(n==0) n = "elem";
    else n = "elem."+n;
    var uval = [];
    var unic = x.filter(function(elem, index, self){
        if(uval.indexOf(eval(n)) < 0){
            uval.push(eval(n));
            return index == self.indexOf(elem);
        }
    })
    return unic;
}

استخدم هذا مثل هذا

tags_obj = [{name:"milad"},{name:"maziar"},{name:"maziar"}]
tags_arr = ["milad","maziar","maziar"]
console.log(oaunic(tags_obj,"name")) //for object
console.log(oaunic(tags_arr)) //for array

يعد استخدام ميزات Ecma الجديدة أمرًا رائعًا ولكن ليس لدى جميع المستخدمين ميزات متوفرة حتى الآن.

بعد إرفاق تعليمات برمجية سيتم إرفاق دالة جديدة باسم مميزة كائن "مصفوفة العمومية". إذا كنت تحاول الحصول على قيم مميزة لمجموعة من الكائنات ، فيمكنك تمرير اسم القيمة للحصول على القيم المميزة لهذا النوع.

Array.prototype.distinct = function(item){   var results = [];
for (var i = 0, l = this.length; i < l; i++)
    if (!item){
        if (results.indexOf(this[i]) === -1)
            results.push(this[i]);
        } else {
        if (results.indexOf(this[i][item]) === -1)
            results.push(this[i][item]);
    }
return results;};

تحقق من منصبي في CodePen عن العرض التوضيحي.


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

var unique = {};
var distinct = [];
for( var i in array ){
 if( typeof(unique[array[i].age]) == "undefined"){
  distinct.push(array[i].age);
 }
 unique[array[i].age] = 0;
}

هنا هو عرض العمل: http://jsfiddle.net/jbUKP/1

سيكون هذا هو O (n) حيث n هو عدد الكائنات في الصفيف و m هو عدد القيم الفريدة. لا توجد طريقة أسرع من O (n) لأنه يجب عليك فحص كل قيمة مرة واحدة على الأقل.

أداء

http://jsperf.com/filter-versus-dictionary عندما أجريت هذا القاموس كان أسرع 30٪.


unique(obj, prop) {
    let result = [];
    let seen = new Set();

    Object.keys(obj)
        .forEach((key) => {
            let value = obj[key];

            let test = !prop
                ? value
                : value[prop];

            !seen.has(test)
                && seen.add(test)
                && result.push(value);
        });

    return result;
}






unique