配列のなかから重複を取り除くにはどうすればよいでしょうか? { 0, 1, 2, 3, 0, 1, 2, 5, } から重複している部分を取り除いて { 0, 1, 2, 3, 5, }にするにはどうすればいいでしょうか?
C#の場合
C#の場合はDistinctメソッドを使います。
1 2 3 4 5 6 7 8 9 10 11 12 |
using System; using System.Linq; public class Program { static void Main() { int[] ints = { 0, 1, 2, 3, 0, 1, 2, 5, }; ints = ints.Distinct().ToArray(); Console.WriteLine(string.Join(" ", ints)); } } |
オブジェクトの場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System; using System.Linq; public class MyClass { public MyClass(int id, string name) { Id = id; Name = name; } public string Name { get; set; } public int Id { get; set; } } public class Program { static MyClass[] CreateArray() { return new MyClass[]{ new MyClass(0, "aaa"), new MyClass(1, "abc"), new MyClass(2, "xxx"), new MyClass(3, "xyz"), new MyClass(3, "xyz"), // IdとNameが同じであってもオブジェクトとしては別物 }; } static void Main() { MyClass[] myClasses = CreateArray(); myClasses = myClasses.Distinct().ToArray(); foreach (MyClass myClass in myClasses) Console.WriteLine($"Id:{myClass.Id}, Name:{myClass.Name}"); } } |
IdとNameが同じであってもオブジェクトとしては別物なので重複であるとみなされず削除されていません。
IdとNameが同じである場合、重複とみなして処理をさせるためには以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public class EqualityComparer : IEqualityComparer<MyClass> { public bool Equals(MyClass x, MyClass y) { if (ReferenceEquals(x, y)) return true; if (x is null || y is null) return false; return (x.Id == y.Id && x.Name == y.Name); // ここで return (x.Id == y.Id);とするとIdのみが同じであっても重複データとして処理することができる } // return 0; でも動作するが、 // このメソッドはコレクション内での効率的な挿入と参照に用いられるのできちんと書いたほうがよい。 public int GetHashCode(MyClass obj) { return obj.Id ^ obj.Name.GetHashCode(); } } public class Program { static void Main() { MyClass[] myClasses = CreateArray(); myClasses = myClasses.Distinct(new EqualityComparer()).ToArray(); foreach (MyClass myClass in myClasses) Console.WriteLine($"Id:{myClass.Id}, Name:{myClass.Name}"); } } |
JavaScriptならどうなる?
配列の重複を削除する方法はいくつかありますが、Setオブジェクトを使う方法がおすすめです。Setオブジェクトは一意の値を入れておくことができるコレクションで、複数の同じ値を入れても一意な値だけが残ります。これをArray.from関数で配列に変換します。
1 2 3 4 5 6 7 |
const array1 = [1, 2, 3, 2, 3, 4]; const array2 = Array.from(new Set(array1)) console.log(array2); // [ 1, 2, 3, 4 ] // これでもOK const array3 = [...new Set(array1)]; console.log(array3); // [ 1, 2, 3, 4 ] 上と同じ |
オブジェクトの場合はどうなるでしょうか? やはりC#と同じで普通の方法では、データが同じでもオブジェクトとしては別物の場合は重複とみなされません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class MyClass{ constructor(id, name){ this.Id = id; this.Name = name; } } function createArray(){ const arr = []; arr.push(new MyClass(0, "aaa")); arr.push(new MyClass(1, "abc")); arr.push(new MyClass(2, "xxx")); arr.push(new MyClass(3, "xyz")); arr.push(new MyClass(3, "xyz")); // データとしては同じだが別オブジェクト return arr; } const array1 = createArray(); const array2 = [...new Set(array1)]; console.log(array2); |
出力結果
1 2 3 4 5 6 7 |
[ {"Id": 0, "Name": "aaa"}, {"Id": 1, "Name": "abc"}, {"Id": 2, "Name": "xxx"}, {"Id": 3, "Name": "xyz"}, {"Id": 3, "Name": "xyz"} // 重複が削除されていない ] |
この場合は重複を削除した結果を格納する配列を新しく作り、その配列に存在しない値だけ追加していくという愚直な方法をとるしかありません。
1 2 3 4 5 6 |
const array3 = [] array1.forEach(currentValue => { if (!array3.find(element => element.Id === currentValue.Id && element.Name === currentValue.Name)) array3.push(currentValue) }); console.log(array3) |
出力結果
1 2 3 4 5 6 |
[ {"Id": 0, "Name": "aaa"}, {"Id": 1, "Name": "abc"}, {"Id": 2, "Name": "xxx"}, {"Id": 3, "Name": "xyz"} // 重複が削除されている ] |