リストコレクションオブジェクトの重複排除と属性による重複排除の8つの方法-Java基本サマリーシリーズの第6部

最近、Javaの基礎についての記事を書いていますが、教科書のように知識のポイントについての記事はあまり意味がないので書きたくありません。基本的な知識が多すぎます。この知識を要約する方法、長所と短所を要約する方法、またはシナリオを使用する方法は、知識の昇華ですそこで、Javaの基本的な知識を掘り下げて、全体的な要約を作成したいと思います。

  • Javaでファイルを作成および書き込む5つの方法を要約します
  • Javaでファイルからデータを読み取る6つの方法を要約します
  • Javaでフォルダを作成する4つの方法とその長所と短所を要約します
  • Javaでファイルやフォルダを削除する7つの方法を要約します
  • Javaでファイルをコピーおよびカットする5つの方法を要約します

たとえば、私は以前に上記のコンテンツを作成しました。Javaの基本的な知識の要約シリーズに興味がある場合は、私のブログをフォローできます(私のブログのアドレスは記事の最後に記載されています)

1.この記事の要約

この記事では、リストコレクション要素の重複排除のための8つのメソッドを記述したいと思います。実際、柔軟な使用により、8つの順列と組み合わせはないかもしれませんが、18のメソッドがあるかもしれません。

  • オブジェクト要素の全体的な重複排除のための4つの方法
  • オブジェクト属性に従って重複排除する4つの方法

以下のテスト内容を説明するために、最初にいくつかの初期化データを実行します

public class ListRmDuplicate {
  private List<String> list;
  private List<Player> playerList;

  @BeforeEach
  public void setup() {
    list  =  new ArrayList<>();
    list.add("kobe");
    list.add("james");
    list.add("curry");
    list.add("zimug");
    list.add("zimug");

    playerList= new ArrayList<>();
    playerList.add(new Player("kobe","10000"));  //科比万岁
    playerList.add(new Player("james","32"));
    playerList.add(new Player("curry","30"));
    playerList.add(new Player("zimug","27"));   // 注意这里名字重复
    playerList.add(new Player("zimug","18"));   //注意这里名字和年龄重复
    playerList.add(new Player("zimug","18")); //注意这里名字和年龄重复

  }
}

Playerオブジェクトは、2つのメンバー変数nameとageを持つ通常のJavaオブジェクトであり、パラメーター化されたコンストラクター、toString、equalsとhashCodeメソッド、およびGET / SETメソッドを実装します。

次に、コレクション要素の全体的な重複排除

次の4つのメソッドは、リスト内の文字列型をコレクション要素オブジェクト全体の単位として重複排除します。ListがObjectオブジェクトの場合、オブジェクトのequalsメソッドとhashCodeメソッドを実装する必要があります。List<String>重複排除のコード実装メソッドは、重複排除のコード実装メソッドと同じです。

最初の方法

セットのデータ構造自体に重複排除の機能があるため、最初にリストのデータをセットに入れることは誰にとっても最も簡単です。したがって、SETがリストに変換された後、それは重複排除の結果になります。HashSet自体は順序付けられておらず、TreeSetの並べ替えはリスト要素の元の順序ではないため、このメソッドは重複排除後にリスト要素の元の順序を変更します。

@Test
void testRemove1()  {
  /*Set<String> set = new HashSet<>(list);
  List<String> newList = new ArrayList<>(set);*/

  //去重并排序的方法(如果是字符串,按字母表排序。如果是对象,按Comparable接口实现排序)
  //List<String> newList = new ArrayList<>(new TreeSet<>(list));

  //简写的方法
  List<String> newList = new ArrayList<>(new HashSet<>(list));

  System.out.println( "去重后的集合: " + newList);
}

コンソールの印刷結果は次のとおりです。

去重后的集合: [kobe, james, zimug, curry]

2番目の方法

使い方は比較的簡単です。まず、streamメソッドを使用してコレクションをストリームに変換し、次にdistinctを使用して重複を削除し、最後にStreamストリームコレクションをリストとして収集します。

@Test
void testRemove2()  {
  List<String> newList = list.stream().distinct().collect(Collectors.toList());

  System.out.println( "去重后的集合: " + newList);
}

コンソールの印刷結果は次のとおりです。

去重后的集合: [kobe, james, curry, zimug]

3番目のメソッドこのメソッドが使用されますset.add(T)。T要素がコレクションにすでに存在する場合、falseを返します。このメソッドを使用して、データが重複しているかどうかを判断し、重複していない場合は、新しいnewListに配置します。このnewListが最終的な重複排除の結果になります。

//三个集合类list、newList、set,能够保证顺序
@Test
void testRemove3()  {

  Set<String> set = new HashSet<>();
  List<String> newList = new  ArrayList<>();
  for (String str :list) {
    if(set.add(str)){ //重复的话返回false
      newList.add(str);
    }
  }
  System.out.println( "去重后的集合: " + newList);

}

コンソールの印刷結果は、2番目の方法と一致しています。

4番目の方法この方法は、重複排除にSetコレクションを使用するという考えから脱却しましたが、重複排除newList.contains(T)を実現するために、新しいリストにデータを追加するときにデータがすでに存在するかどうか、および追加しないかどうかを判断する方法を使用します。。効果。

//优化 List、newList、set,能够保证顺序
@Test
void testRemove4() {

  List<String> newList = new  ArrayList<>();
  for (String cd:list) {
    if(!newList.contains(cd)){  //主动判断是否包含重复元素
      newList.add(cd);
    }
  }
  System.out.println( "去重后的集合: " + newList);

}

コンソールの印刷結果は、2番目の方法と一致しています。

第三に、コレクション要素オブジェクトの属性に従って重複排除します

実際、実際の作業では、コレクション要素オブジェクトの全体的な重複排除に応じた重複排除の適用はまだ比較的少なく、要素オブジェクトの特定の属性に応じて重複排除を行う必要があります。これを見て、戻って上記で作成した初期化データを見てくださいplayerList。繰り返される要素のいくつかとメンバー変数の繰り返しに特に注意してください。

最初の方法は、TreeSetのComparatorインターフェースを実装することです。Playerのname属性に従って重複排除する場合は、Comparatorインターフェースで名前を比較できます。コンパレータインターフェイスを実装する2つの方法を以下に示します。

  • ラムダ式:(o1, o2) -> o1.getName().compareTo(o2.getName())
  • メソッドリファレンス:Comparator.comparing(Player::getName)
@Test
void testRemove5() {
  //Set<Player> playerSet = new TreeSet<>((o1, o2) -> o1.getName().compareTo(o2.getName()));
  Set<Player> playerSet = new TreeSet<>(Comparator.comparing(Player::getName));
  playerSet.addAll(playerList);

  /*new ArrayList<>(playerSet).forEach(player->{
    System.out.println(player.toString());
  });*/
  //将去重之后的结果打印出来
  new ArrayList<>(playerSet).forEach(System.out::println);
}

出力は次のとおりです。3つのzimugの名前が重複しており、他の2つは重複排除されています。ただし、TreeSetが使用されているため、リスト内の要素は並べ替えられます。

Player{name='curry', age='30'}
Player{name='james', age='32'}
Player{name='kobe', age='10000'}
Player{name='zimug', age='27'}

2番目の方法この方法は、あなたが素晴らしいことを示すためにインターネット上の多くの記事で使用されていますが、私の意見では、私はズボンとおならを脱いでいます。そんな方法があるとみんな言われているので、苦手なようには書きません。この方法が「ズボンとおならを脱ぐ」と言うのはなぜですか?

  • 最初にstream()を使用して、リストコレクションをストリームに変換します
  • 次に、collectとtoCollectionを使用して、ストリームをコレクションに変換します
  • その後、残りは最初の方法と同じです

最初の2つのステップでズボンを脱いでおならをしませんでしたか?見てみると、実際のアプリケーションはあまり意味がありませんが、Streamの使用法を学ぶ場合は、そのような例を考え出すことが望ましいです。

@Test
void testRemove6() {
  List<Player> newList = playerList.stream().collect(Collectors
          .collectingAndThen(
                  Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Player::getName))),
                  ArrayList::new));

  newList.forEach(System.out::println);
}

コンソールのプリントアウトは最初の方法と同じです。

3番目の方法

この方法も作者が推奨する方法であり、一見コード量が多いように見えますが、実は比較的簡単な方法です。

述語(これを述語と呼ぶ人もいます。英語の観点からは、述語として名詞として翻訳でき、動詞としても述語として翻訳できます)。述語は、主語を変更するために使用されます。たとえば、歌うのが好きな鳥は、主語の範囲を制限するために使用される述語です。ですから、私たちはここでフィルタリングするだけでなく、主題の範囲を制限するためにここにいるので、述語として翻訳する方が適切だと思います。何をしたいのか、合理的で覚えやすいと思うことは何でもできます。

  • まず、フィルターする述語Predicateを定義し、フィルター条件はdistinctByKeyです。述語は保持するtrue要素を返し、false要素は除外されます。
  • もちろん、私たちの要件は重複する要素を除外することです。重複排除ロジックは、マップのputIfAbsentによって実装されます。putIfAbsentメソッドは、キーと値のペアを追加します。マップセットにキーに対応する値がない場合は、直接追加してnullを返します。対応する値が既に存在する場合は、元の値のままです。
  • putIfAbsentがnullを返す場合、データが正常に追加された(繰り返されない)ことを意味します。putIfAbsentがvalue(value == null:false)を返す場合、distinctByKey述語の条件を満たす要素は除外されます。

このメソッドはコードの量を増やしたように見えますが、distinctByKey述語メソッドは一度定義するだけでよく、無期限に再利用できます。

@Test
void testRemove7() {
  List<Player> newList = new ArrayList<>();
  playerList.stream().filter(distinctByKey(p -> p.getName()))  //filter保留true的值
          .forEach(newList::add);

  newList.forEach(System.out::println);
}

static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
  Map<Object,Boolean> seen = new ConcurrentHashMap<>();
  //putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。
  //如果返回null表示添加数据成功(不重复),不重复(null==null :TRUE)
  return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

出力は次のとおりです。3つのzimugの名前が重複しており、他の2つは重複排除されています。そして、リストの元の順序を混乱させませんでした

Player{name='kobe', age='10000'}
Player{name='james', age='32'}
Player{name='curry', age='30'}
Player{name='zimug', age='27'}

4番目のメソッド4番目のメソッドは実際には新しいメソッドではありません。上記の例はすべて、重複排除する特定のオブジェクト属性に基づいています。特定の要素に従って重複排除する場合は、上記の3つのメソッドを変更する必要があります。 。そのうちの1つだけを改造しましたが、他の改造の原則は同じです。つまり、複数の比較プロパティを合計し、それらをStringプロパティとして比較します。

@Test
void testRemove8() {
  Set<Player> playerSet = new TreeSet<>(Comparator.comparing(o -> (o.getName() + "" + o.getAge())));

  playerSet.addAll(playerList);

  new ArrayList<>(playerSet).forEach(System.out::println);
}

私のブログをフォローすることを歓迎します、多くのブティックコレクションがあります

  • この記事は、出典を示して複製されています(接続を添付する必要があり、テキストのみを複製することはできません):レターブラザーのブログ

あなたがそれがあなたに役立つと思うなら、私のためにそれを好きにして共有してください!あなたのサポートは私の尽きることのない創造的な動機です!また、最近、以下のような高品質なコンテンツを出力しておりますので、よろしくお願いいたします。

おすすめ

転載: blog.csdn.net/hanxiaotongtong/article/details/108442705