web-dev-qa-db-ja.com

ng-repeatで重複する結果を除外する方法

私はJSONファイル上で単純なng-repeatを実行していて、カテゴリ名を取得したいのです。それぞれがカテゴリに属する​​オブジェクトは約100個ありますが、カテゴリは約6個しかありません。

私の現在のコードはこれです:

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

出力は100種類のオプションで、ほとんどが重複しています。 Angularを使用して{{place.category}}が既に存在するかどうかを確認し、既に存在する場合はオプションを作成しないようにする方法

編集:私のJavascriptの$scope.places = JSON dataでは、明確にするためだけに

127
JVG

AngularUIから入手可能なuniqueフィルタ(ここで入手可能なソースコード: AngularUI unique filter )を直接使用することもできます。 -options(またはng-repeat)。

<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>
139
jpmorin

あるいは、lodashを使って独自のフィルタを書くこともできます。

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

angular.filter モジュールで 'unique'(エイリアス:uniq)フィルタを使うことができます

使用法: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:顧客IDでフィルタリングします。つまり、重複する顧客を削除します。

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

結果
顧客リスト:
foo 10
小節20
バズ30

30
a8m

このコードは私のために働きます。

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");
15
Eduardo Ortiz

あなたがカテゴリーをリストしたいならば、私はあなたがビューであなたの意図を明白に述べるべきであると思います。

<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;
}, []);
5
Tosh

これは簡単で一般的な例です。

フィルター

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>
4
Erik Trautman

私は、@ thethakuriの回答を拡張して、独自のメンバーに任意の深さを許可することにしました。これがコードです。これは、この機能のためだけにAngularUIモジュール全体を含めたくない人のためのものです。すでにAngular UIを使用している場合は、この答えを無視してください。

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>
3
kennasoft

これを行うためのテンプレートのみの方法があります(ただし、順序は維持されません)。さらに、結果も順序付けされます。これは、ほとんどの場合に役立ちます。

<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
shoesel

更新

Setの使用を推奨していましたが、申し訳ありませんがng-repeatやng-repeatはarrayでしか機能しないのでMapでは使えません。だからこの答えを無視してください。いずれにしても、一方で重複を除外する必要がある場合は、他の人がangular filtersを使用して言ったように、これが 開始セクションへのリンク です。


古い答え

配列データ構造の代わりに 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
CommonSenseCode

私はオブジェクトではなく文字列の配列を持っていました、そして私はこのアプローチを使いました:

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(); 
    }

  };
}
1
Helzgate

ネストしたキーに基づいて一意のデータを取得したい場合は、

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'">
1
thethakuri

誰もが自分のバージョンの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
L S

上記のフィルタのどれも私の問題を解決しなかったので私は公式からフィルタをコピーしなければなりません github doc。 そしてそれから上記の答えで説明されているようにそれを使ってください

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

戻り関数(items、filterOn){

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
Black Mamba

このフィルタを追加してください。

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
Shawn Dotey

これはやり過ぎかもしれませんが、私にとってはうまくいきます。

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;
}

個別の機能は、上で定義されたcontains機能に依存します。これはarray.distinct(prop);と呼びます。ここでpropは区別したいプロパティです。

だから$scope.places.distinct("category");と言うことができます

0
Ikechi Michael

あなた自身の配列を作成してください。

<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);
    }
});
0
Akhilesh Kumar