TypeScriptでは、このパターンを頻繁に使用します。
class Vegetable {
constructor(public id: number, public name: string) {
}
}
var vegetable_array = new Array<Vegetable>();
vegetable_array.Push(new Vegetable(1, "Carrot"));
vegetable_array.Push(new Vegetable(2, "Bean"));
vegetable_array.Push(new Vegetable(3, "Peas"));
var id = 1;
var collection = vegetable_array.filter( xvegetable => {
return xvegetable.id == id;
});
var item = collection.length < 1 ? null : collection[0];
console.info( item.name );
LINQ SingleOrDefault
メソッドに似たJavaScript拡張を作成することを考えています。配列にない場合はnull
を返します:
var item = vegetable.singleOrDefault( xvegetable => {
return xvegetable.id == id});
私の質問は、カスタムインターフェイスを作成せずにこれを達成する別の方法があるかどうかです。
常に Array.prototype.filter を次のように使用できます。
var arr = [1,2,3];
var notFoundItem = arr.filter(id => id === 4)[0]; // will return undefined
var foundItem = arr.filter(id => id === 3)[0]; // will return 3
編集
私の答えはFirstOrDefault
ではなくSingleOrDefault
に適用されます。SingleOrDefault
は、一致するものが1つだけであるかどうかを確認します。私の場合(およびコード内)、別の一致を確認せずに最初の一致を返します。
ところで、SingleOrDefault
を実現したい場合は、これを変更する必要があります。
var item = collection.length < 1 ? null : collection[0];
に
if(collection.length > 1)
throw "Not single result....";
return collection.length === 0 ? null : collection[0];
配列内の1つのアイテムを検索する場合は、 ES6 find method を使用することをお勧めします。
const inventory = [
{ name: 'apples', quantity: 2 },
{ name: 'bananas', quantity: 0 },
{ name: 'cherries', quantity: 5 }
];
const result = inventory.find(fruit => fruit.name === 'cherries');
console.log(result) // { name: 'cherries', quantity: 5 }
collection[0]
と書く必要がないため、読みやすくなります。
ところで、C#のSingleOrDefault
は、複数の要素が見つかった場合に例外をスローします。ここでは、FirstOrDefault
拡張機能を作成しようとしています。
再利用が不要な場合は、単純な reduce 関数を適用してsingleOrDefault
を実装できます。
この場合、reducer関数は、配列が空でない場合にのみ計算されます。長さが1より大きい場合にスローされます。そうでない場合は、唯一の要素を返します。配列が空の場合、reduce関数のデフォルト値パラメーターが返されます。この場合はnull
です。
例えば:
[].reduce(function(acc, cur, idx, src) {
if (src.length > 1) {
throw 'More than one found';
}
return src[0];
}, null);
現在、TypeScriptで厳密に型指定されたクエリ可能なコレクションを提供するライブラリがあります。
ライブラリはts-generic-collectionsと呼ばれます。
GitHubのソースコード:
https://github.com/VeritasSoftware/ts-generic-collections
このライブラリを使用すると、次のようにクエリを作成できます。
let owners = new List<Owner>();
let owner = new Owner();
owner.id = 1;
owner.name = "John Doe";
owners.add(owner);
owner = new Owner();
owner.id = 2;
owner.name = "Jane Doe";
owners.add(owner);
let pets = new List<Pet>();
let pet = new Pet();
pet.ownerId = 2;
pet.name = "Sam";
pet.sex = Sex.M;
pets.add(pet);
pet = new Pet();
pet.ownerId = 1;
pet.name = "Jenny";
pet.sex = Sex.F;
pets.add(pet);
//query to get owners by their pet's gender/sex
let ownersByPetSex = owners.join(pets, owner => owner.id, pet => pet.ownerId, (x, y) => new OwnerPet(x,y))
.groupBy(x => [x.pet.sex])
.select(x => new OwnersByPetSex(x.groups[0], x.list.select(x => x.owner)));
expect(ownersByPetSex.toArray().length === 2).toBeTruthy();
expect(ownersByPetSex.toArray()[0].sex == Sex.F).toBeTruthy();
expect(ownersByPetSex.toArray()[0].owners.length === 1).toBeTruthy();
expect(ownersByPetSex.toArray()[0].owners.toArray()[0].name == "John Doe").toBeTruthy();
expect(ownersByPetSex.toArray()[1].sex == Sex.M).toBeTruthy();
expect(ownersByPetSex.toArray()[1].owners.length == 1).toBeTruthy();
expect(ownersByPetSex.toArray()[1].owners.toArray()[0].name == "Jane Doe").toBeTruthy();