डुप्लिकेट परिणामों को एनजी-रिपीट फ़िल्टर कैसे करें


131

मैं ng-repeatएक JSON फ़ाइल पर एक साधारण चला रहा हूं और श्रेणी के नाम प्राप्त करना चाहता हूं। लगभग 100 ऑब्जेक्ट हैं, जिनमें से प्रत्येक एक श्रेणी से संबंधित है - लेकिन लगभग 6 श्रेणियां हैं।

मेरा वर्तमान कोड यह है:

<select ng-model="orderProp" >
  <option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>

आउटपुट 100 विभिन्न विकल्प हैं, ज्यादातर डुप्लिकेट हैं। मैं {{place.category}}पहले से मौजूद है या नहीं, यह जांचने के लिए कि मैं कोणीय का उपयोग कैसे करूं और अगर यह पहले से मौजूद है तो कोई विकल्प नहीं बनाएं?

संपादित करें: मेरी जावास्क्रिप्ट में $scope.places = JSON data, बस स्पष्ट करने के लिए


1
आप सिर्फ अपने $ स्कोप की कटौती क्यों नहीं करते हैं। jquery का नक्शा api.jquery.com/map
aazimok

आपका अंतिम कार्य समाधान क्या था? यह है कि यह ऊपर है या वहाँ है कुछ JS डी-
डुबकी

मैं इसका समाधान जानना चाहता हूं। कृपया एक अनुवर्ती पोस्ट करें। धन्यवाद!
jdstein1

@ jdstein1 मैं TLDR के साथ शुरू करूंगा: नीचे दिए गए उत्तरों का उपयोग करें, या किसी सरणी में केवल अनन्य मानों को फ़िल्टर करने के लिए वेनिला जावास्क्रिप्ट का उपयोग करें। मैंने क्या किया: अंत में, यह मेरे तर्क और एमवीसी की मेरी समझ के साथ एक समस्या थी। मैं MongoDB से डेटा लोड कर रहा था और डेटा की एक डंप मांग रहा था और चाहता था कि कोणीय जादुई तरीके से इसे केवल अनूठे स्थानों तक फ़िल्टर कर दूं। समाधान, जैसे कि अक्सर मामला, आलसी होने से रोकने के लिए और मेरे डीबी मॉडल को ठीक करने के लिए था - मेरे लिए, यह मोंगो को बुला रहा था db.collection.distinct("places"), जो कि कोणीय के भीतर करने से कहीं बेहतर था! अफसोस की बात है कि यह सभी के लिए काम नहीं करेगा।
जेवीजी

अद्यतन के लिए धन्यवाद!
jdstein1

जवाबों:


142

आप इस्तेमाल कर सकते हैं अद्वितीय (स्रोत यहाँ उपलब्ध कोड: AngularUI से फिल्टर AngularUI अद्वितीय फिल्टर ) है और यह सीधे का उपयोग एनजी-विकल्प में (या NG-दोहराने)।

<select ng-model="orderProp" ng-options="place.category for place in places | unique:'category'">
    <option value="0">Default</option>
    // unique options from the categories
</select>

33
उन लोगों के लिए जो काम कर रहे AngularUI के अनूठे फ़िल्टर प्राप्त नहीं कर सकते हैं: फ़िल्टर एक अलग मॉड्यूल में हैं: जैसे कि आपको इसे अपने मॉड्यूल में एक अतिरिक्त संदर्भ के रूप में शामिल करना होगा angular.module('yourModule', ['ui', 'ui.filters']);। जब तक मैं AngularUI js फ़ाइल के अंदर देख नहीं लिया, तब तक रुक गया था।
GFoley83

8
uniqueफिल्टर वर्तमान के हिस्से के रूप में पाया जा सकता AngularJS यूआई Utils
निक

2
उई के बर्तनों के नए संस्करण में, आप बस अपने आप पर ui.unique शामिल कर सकते हैं। मॉड्यूल के लिए बोवर इंस्टॉल का उपयोग करें।
उदाहरण

यदि आप AngularUI और उसकी संपूर्णता को शामिल नहीं करना चाहते हैं, लेकिन अनन्य फ़िल्टर का उपयोग करना चाहते हैं, तो आप बस अपने ऐप में अनूठे .js स्रोत को पेस्ट कर सकते हैं, फिर angular.module('ui.filters')अपने ऐप नाम में बदल सकते हैं।
चकेड़ा

37

या आप अपने स्वयं के फ़िल्टर को लॉश का उपयोग करके लिख सकते हैं।

app.filter('unique', function() {
    return function (arr, field) {
        return _.uniq(arr, function(a) { return a[field]; });
    };
});

हैलो माइक, वास्तव में बहुत सुंदर लग रहा है, लेकिन जब मैं एक फिल्टर को अद्वितीय: स्थिति [मेरे क्षेत्र का नाम] की तरह पास करने के लिए उम्मीद के मुताबिक काम नहीं करता है, तो यह केवल सभी अद्वितीय मूर्तियों की वांछित सूची के विपरीत पहला परिणाम लौटाता है। कोई भी अनुमान क्यों?
सिनसिन

3
हालांकि मैंने अंडरस्कोर का उपयोग किया, लेकिन इस समाधान ने एक आकर्षण की तरह काम किया। धन्यवाद!
जॉन ब्लैक

बहुत ही सुंदर समाधान।
जेडी स्मिथ

1
लताश अंडरस्कोर का एक कांटा है। इसमें बेहतर प्रदर्शन और अधिक उपयोगिताओं हैं।
माइक वार्ड

2
in लिशेश v4 _.uniqBy(arr, field);नेस्टेड गुणों के लिए काम करना चाहिए
ijavid

30

आप angular.filter मॉड्यूल में 'यूनिक' ( एलियासेस : यूनीक ) फिल्टर का उपयोग कर सकते हैं

उपयोग: colection | uniq: 'property'
आप नेस्टेड गुणों द्वारा फ़िल्टर भी कर सकते हैं: colection | uniq: 'property.nested_property'

आप क्या कर सकते हैं, ऐसा कुछ है ..

function MainController ($scope) {
 $scope.orders = [
  { id:1, customer: { name: 'foo', id: 10 } },
  { id:2, customer: { name: 'bar', id: 20 } },
  { id:3, customer: { name: 'foo', id: 10 } },
  { id:4, customer: { name: 'bar', id: 20 } },
  { id:5, customer: { name: 'baz', id: 30 } },
 ];
}

HTML: हम ग्राहक आईडी द्वारा फ़िल्टर करते हैं, अर्थात डुप्लिकेट ग्राहकों को हटाते हैं

<th>Customer list: </th>
<tr ng-repeat="order in orders | unique: 'customer.id'" >
   <td> {{ order.customer.name }} , {{ order.customer.id }} </td>
</tr>

परिणाम
ग्राहक सूची:
फू 10
बार 20
बाज 30


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

@GregGrater क्या आप अपनी समस्या के समान उदाहरण वस्तु प्रदान कर सकते हैं?
a8m

धन्यवाद @ एरियल एम। यहां डेटा का एक उदाहरण दिया गया है:
ग्रेग ग्रैटर

कोणीय के किन संस्करणों के साथ यह संगत है?
आईकन

15

यह कोड मेरे लिए काम करता है।

app.filter('unique', function() {

  return function (arr, field) {
    var o = {}, i, l = arr.length, r = [];
    for(i=0; i<l;i+=1) {
      o[arr[i][field]] = arr[i];
    }
    for(i in o) {
      r.push(o[i]);
    }
    return r;
  };
})

और फिर

var colors=$filter('unique')(items,"color");

2
L की परिभाषा l = arr = अपरिभाषित होनी चाहिए? arr.length: 0 क्योंकि अन्यथा कोणीयज में एक पार्सिंग त्रुटि है
गेरिट

6

यदि आप श्रेणियों को सूचीबद्ध करना चाहते हैं, तो मुझे लगता है कि आपको अपना इरादा स्पष्ट रूप से दृश्य में बताना चाहिए।

<select ng-model="orderProp" >
  <option ng-repeat="category in categories"
          value="{{category}}">
    {{category}}
  </option>
</select>

नियंत्रक में:

$scope.categories = $scope.places.reduce(function(sum, place) {
  if (sum.indexOf( place.category ) < 0) sum.push( place.category );
  return sum;
}, []);

क्या आप इसे थोड़ा और समझा सकते हैं। मैं प्रत्येक अद्वितीय श्रेणी के लिए एक पंक्ति में वें तत्वों को दोहराना चाहता हूं। क्या जेएस सिर्फ जेएस फाइल में जाता है जहां नियंत्रक परिभाषित किया गया है?
निशान 1234

यदि आप विकल्पों को समूहीकृत करना चाहते हैं, तो यह अलग प्रश्न है। आप ऑप्टग्रेग तत्व में देखना चाहते हैं। कोणीय ऑप्टोग्रुप का समर्थन करता है। निर्देशन group byमें अभिव्यक्ति की खोज select
तोश

क्या इस मामले में होगा कि कोई स्थान जोड़ा / हटाया गया है? क्या संबंधित श्रेणी को केवल स्थानों पर ही जोड़ा / हटाया जाएगा?
ग्रेग ग्रेट

4

यहाँ एक सीधा और सामान्य उदाहरण है।

फ़िल्टर:

sampleApp.filter('unique', function() {

  // Take in the collection and which field
  //   should be unique
  // We assume an array of objects here
  // NOTE: We are skipping any object which
  //   contains a duplicated value for that
  //   particular key.  Make sure this is what
  //   you want!
  return function (arr, targetField) {

    var values = [],
        i, 
        unique,
        l = arr.length, 
        results = [],
        obj;

    // Iterate over all objects in the array
    // and collect all unique values
    for( i = 0; i < arr.length; i++ ) {

      obj = arr[i];

      // check for uniqueness
      unique = true;
      for( v = 0; v < values.length; v++ ){
        if( obj[targetField] == values[v] ){
          unique = false;
        }
      }

      // If this is indeed unique, add its
      //   value to our values and push
      //   it onto the returned array
      if( unique ){
        values.push( obj[targetField] );
        results.push( obj );
      }

    }
    return results;
  };
})

मार्कअप:

<div ng-repeat = "item in items | unique:'name'">
  {{ item.name }}
</div>
<script src="your/filters.js"></script>

यह ठीक काम करता है, लेकिन यह Cannot read property 'length' of undefinedलाइन में सांत्वना में एक त्रुटि फेंकता हैl = arr.length
आत्मा खानेवाला

4

मैंने अद्वितीय सदस्य के लिए किसी भी गहराई की अनुमति देने के लिए @ थथुरी के उत्तर का विस्तार करने का निर्णय लिया। यहाँ कोड है। यह उन लोगों के लिए है जो इस कार्यक्षमता के लिए पूरे AngularUI मॉड्यूल को शामिल नहीं करना चाहते हैं। यदि आप पहले से ही AngularUI का उपयोग कर रहे हैं, तो इस उत्तर को अनदेखा करें:

app.filter('unique', function() {
    return function(collection, primaryKey) { //no need for secondary key
      var output = [], 
          keys = [];
          var splitKeys = primaryKey.split('.'); //split by period


      angular.forEach(collection, function(item) {
            var key = {};
            angular.copy(item, key);
            for(var i=0; i<splitKeys.length; i++){
                key = key[splitKeys[i]];    //the beauty of loosely typed js :)
            }

            if(keys.indexOf(key) === -1) {
              keys.push(key);
              output.push(item);
            }
      });

      return output;
    };
});

उदाहरण

<div ng-repeat="item in items | unique : 'subitem.subitem.subitem.value'"></div>

2

मेरे पास एक स्ट्रिंग थी, ऑब्जेक्ट नहीं और मैंने इस दृष्टिकोण का उपयोग किया:

ng-repeat="name in names | unique"

इस फ़िल्टर के साथ:

angular.module('app').filter('unique', unique);
function unique(){
return function(arry){
        Array.prototype.getUnique = function(){
        var u = {}, a = [];
        for(var i = 0, l = this.length; i < l; ++i){
           if(u.hasOwnProperty(this[i])) {
              continue;
           }
           a.push(this[i]);
           u[this[i]] = 1;
        }
        return a;
    };
    if(arry === undefined || arry.length === 0){
          return '';
    }
    else {
         return arry.getUnique(); 
    }

  };
}

2

अपडेट करें

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


पुराना उत्तर

Yo ECMAScript 2015 (ES6) स्टैंडर्ड सेट डेटा संरचना का उपयोग कर सकते हैं , एरे डेटा स्ट्रक्चर के बजाय इस तरह से आप सेट में जोड़ते समय दोहराया मूल्यों को फ़िल्टर करते हैं। (याद रखें सेट दोहराया मूल्यों की अनुमति नहीं देते हैं)। उपयोग करने के लिए वास्तव में आसान:

var mySet = new Set();

mySet.add(1);
mySet.add(5);
mySet.add("some text");
var o = {a: 1, b: 2};
mySet.add(o);

mySet.has(1); // true
mySet.has(3); // false, 3 has not been added to the set
mySet.has(5);              // true
mySet.has(Math.sqrt(25));  // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true

mySet.size; // 4

mySet.delete(5); // removes 5 from the set
mySet.has(5);    // false, 5 has been removed

mySet.size; // 3, we just removed one value

2

इसे करने के लिए केवल एक टेम्प्लेट-तरीका है (यह ऑर्डर को बनाए नहीं रख रहा है, हालांकि)। इसके अलावा, परिणाम भी आदेश दिया जाएगा, जो ज्यादातर मामलों में उपयोगी है:

<select ng-model="orderProp" >
   <option ng-repeat="place in places | orderBy:'category' as sortedPlaces" data-ng-if="sortedPlaces[$index-1].category != place.category" value="{{place.category}}">
      {{place.category}}
   </option>
</select>

2

उपरोक्त में से किसी भी फ़िल्टर ने मेरे मुद्दे को ठीक नहीं किया, इसलिए मुझे आधिकारिक जीथब डॉक से फ़िल्टर को कॉपी करना पड़ा और फिर उपरोक्त उत्तर में बताए अनुसार उपयोग करें

angular.module('yourAppNameHere').filter('unique', function () {

वापसी समारोह (आइटम, फ़िल्टरऑन) {

if (filterOn === false) {
  return items;
}

if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
  var hashCheck = {}, newItems = [];

  var extractValueToCompare = function (item) {
    if (angular.isObject(item) && angular.isString(filterOn)) {
      return item[filterOn];
    } else {
      return item;
    }
  };

  angular.forEach(items, function (item) {
    var valueToCheck, isDuplicate = false;

    for (var i = 0; i < newItems.length; i++) {
      if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
        isDuplicate = true;
        break;
      }
    }
    if (!isDuplicate) {
      newItems.push(item);
    }

  });
  items = newItems;
}
return items;
  };

});

1

ऐसा लगता है कि हर कोई uniqueफ़िल्टर के अपने संस्करण को रिंग में फेंक रहा है, इसलिए मैं यही करूँगा। क्रिटिक का बहुत स्वागत है।

angular.module('myFilters', [])
  .filter('unique', function () {
    return function (items, attr) {
      var seen = {};
      return items.filter(function (item) {
        return (angular.isUndefined(attr) || !item.hasOwnProperty(attr))
          ? true
          : seen[item[attr]] = !seen[item[attr]];
      });
    };
  });

1

यदि आप नेस्टेड कुंजी के आधार पर अद्वितीय डेटा प्राप्त करना चाहते हैं:

app.filter('unique', function() {
        return function(collection, primaryKey, secondaryKey) { //optional secondary key
          var output = [], 
              keys = [];

          angular.forEach(collection, function(item) {
                var key;
                secondaryKey === undefined ? key = item[primaryKey] : key = item[primaryKey][secondaryKey];

                if(keys.indexOf(key) === -1) {
                  keys.push(key);
                  output.push(item);
                }
          });

          return output;
        };
    });

इसे इस तरह से कॉल करें:

<div ng-repeat="notify in notifications | unique: 'firstlevel':'secondlevel'">

0

इस फ़िल्टर को जोड़ें:

app.filter('unique', function () {
return function ( collection, keyname) {
var output = [],
    keys = []
    found = [];

if (!keyname) {

    angular.forEach(collection, function (row) {
        var is_found = false;
        angular.forEach(found, function (foundRow) {

            if (foundRow == row) {
                is_found = true;                            
            }
        });

        if (is_found) { return; }
        found.push(row);
        output.push(row);

    });
}
else {

    angular.forEach(collection, function (row) {
        var item = row[keyname];
        if (item === null || item === undefined) return;
        if (keys.indexOf(item) === -1) {
            keys.push(item);
            output.push(row);
        }
    });
}

return output;
};
});

अपना मार्कअप अपडेट करें:

<select ng-model="orderProp" >
   <option ng-repeat="place in places | unique" value="{{place.category}}">{{place.category}}</option>
</select>

0

यह ओवरकिल हो सकता है, लेकिन यह मेरे लिए काम करता है।

Array.prototype.contains = function (item, prop) {
var arr = this.valueOf();
if (prop == undefined || prop == null) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == item) {
            return true;
        }
    }
}
else {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i][prop] == item) return true;
    }
}
return false;
}

Array.prototype.distinct = function (prop) {
   var arr = this.valueOf();
   var ret = [];
   for (var i = 0; i < arr.length; i++) {
       if (!ret.contains(arr[i][prop], prop)) {
           ret.push(arr[i]);
       }
   }
   arr = [];
   arr = ret;
   return arr;
}

अलग-अलग फ़ंक्शन उपरोक्त परिभाषित फ़ंक्शन पर निर्भर करता है। यह कहा जा सकता है कि array.distinct(prop);जहां प्रॉप वह संपत्ति है जो आप अलग होना चाहते हैं।

तो आप बस कह सकते हैं $scope.places.distinct("category");


0

अपनी खुद की सरणी बनाएँ।

<select name="cmpPro" ng-model="test3.Product" ng-options="q for q in productArray track by q">
    <option value="" >Plans</option>
</select>

 productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
    var index = $scope.productArray.indexOf(value.Product);
    if(index === -1)
    {
        $scope.productArray.push(value.Product);
    }
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.