Identifique duplicatas em uma lista


119

Eu tenho uma lista do tipo inteiro, por exemplo:

[1, 1, 2, 3, 3, 3]

Eu gostaria de um método para retornar todas as duplicatas, por exemplo:

[1, 3]

Qual é a melhor maneira de fazer isso?


2
É garantido que a lista de entrada seja classificada (como em seu exemplo)?
NPE

7
classificar a lista e, em seguida, percorrê-la, mantendo os valores atuais e anteriores. se atual == anterior você tem uma duplicata.
mcfinnigan de

Não, a lista não está necessariamente classificada.
mais fresco de

Respostas:


183

O método addde Setretorna um booleano se um valor já existe (verdadeiro se não existir, falso se já existir, consulte a documentação do conjunto ).

Portanto, apenas itere por meio de todos os valores:

public Set<Integer> findDuplicates(List<Integer> listContainingDuplicates)
{ 
  final Set<Integer> setToReturn = new HashSet<>(); 
  final Set<Integer> set1 = new HashSet<>();

  for (Integer yourInt : listContainingDuplicates)
  {
   if (!set1.add(yourInt))
   {
    setToReturn.add(yourInt);
   }
  }
  return setToReturn;
}

1
Por que você setToReturn? Você não pode simplesmente usar set1.add (yourInt) e retornar set1?
Phil,

3
sim, exatamente. Mas quando um elemento está presente apenas uma vez na lista especificada, o elemento também é adicionado. Veja o exemplo na pergunta: Minha solução retornará [1,3] já que o número 2 é inserido em set1, mas não em setToReturn. Sua solução retornaria [1,2,3] (o que não é o requisito)
leifg

1
Eu sugiro que você use for (Integer yourInt, para evitar boxing e unboxing desnecessários, especialmente porque sua entrada já contém Integers.
Hosam Aly de

1
@JonasThelemann toda a ideia de um conjunto é que ele NÃO pode conter duplicatas. portanto: não importa a frequência com que você adicione 3, sempre acabará apenas uma vez.
leifg

1
A propósito, no caso de HashSetvocê também ter que considerar o fator de carga, por exemplo, quando você especifica uma capacidade inicial de 100, porque você deseja adicionar esse número de elementos, ele é arredondado para a próxima potência de 2 ( 128), o que implica que com o fator de carga padrão de 0.75f, o limite de redimensionamento será 96, portanto, haverá um redimensionamento antes de você adicionar 100elementos. Felizmente, o redimensionamento não é mais tão caro. Com JREs atualizados, o redimensionamento não é mais um novo hashing, os elementos são apenas distribuídos entre seus dois locais de resultado possíveis com base no bit relevante.
Holger

50

Eu precisava de uma solução para isso também. Usei a solução de Leifg e a tornei genérica.

private <T> Set<T> findDuplicates(Collection<T> collection) {

    Set<T> duplicates = new LinkedHashSet<>();
    Set<T> uniques = new HashSet<>();

    for(T t : collection) {
        if(!uniques.add(t)) {
            duplicates.add(t);
        }
    }

    return duplicates;
}

1
Eu sei que isso aconteceu 3 anos depois, mas por que um LinkedHashedSet, ou seja, por que você se preocupa com o pedido?
Ahmad Ragab

4
@AhmadRagab você está certo, LinkedHashSet não é necessário, a menos que você se preocupe com a ordem em que as duplicatas foram encontradas (o que eu acho que fiz na época)
John Strickler

Obrigado pelo acompanhamento!
Ahmad Ragab de

Se você tem tantos dados de entrada que deseja usar esta solução ideal (em vez de classificar a entrada), você também deseja pré-alocar o tamanho dos objetos HashSet (). Sem a pré-alocação, você não obtém o tempo de inserção O (1) ao inserir no HashSet (). Isso ocorre porque a matriz hash interna é redimensionada repetidamente. A média das inserções é algo como o tempo O (log N). Isso significa que o processamento de todos os N itens torna-se O (N log N) quando poderia ser O (N).
johnstosh de

39

Peguei a solução de John Strickler e a refiz para usar a API de streams introduzida no JDK8:

private <T> Set<T> findDuplicates(Collection<T> collection) {
    Set<T> uniques = new HashSet<>();
    return collection.stream()
        .filter(e -> !uniques.add(e))
        .collect(Collectors.toSet());
}

3
isso é meio difícil de ler, não? Você está causando um efeito colateral na operação de fluxo, tornando meio difícil de raciocinar. Mas isso é só eu pensando no estilo funcional. É conciso e provavelmente o caminho mais curto;).
froginvasion

Para listas grandes, você pode fazer isso ser executado em paralelo em vários threads?
johnstosh de

@froginvasion o distinct()método embutido também tem estado. Não consigo pensar em uma operação distinta eficiente (O (n)) que não tenha estado.
wilmol

18

Aqui está uma solução usando Streams com Java 8

// lets assume the original list is filled with {1,1,2,3,6,3,8,7}
List<String> original = new ArrayList<>();
List<String> result = new ArrayList<>();

Você apenas verifica se a frequência deste objeto está mais de uma vez em sua lista. Em seguida, chame .distinct () para ter apenas elementos exclusivos em seu resultado

result = original.stream()
    .filter(e -> Collections.frequency(original, e) > 1)
    .distinct()
    .collect(Collectors.toList());
// returns {1,3}
// returns only numbers which occur more than once

result = original.stream()
    .filter(e -> Collections.frequency(original, e) == 1)
    .collect(Collectors.toList());
// returns {2,6,8,7}
// returns numbers which occur only once

result = original.stream()
    .distinct()
    .collect(Collectors.toList());
// returns {1,2,3,6,8,7}
// returns the list without duplicates

1
Isso é bom em termos de legibilidade, mas é MUITO ruim para o desempenho. Collections::frequencyé O (n). Ele precisa percorrer toda a coleção para encontrar a frequência de um item. E estamos chamando isso uma vez para cada item da coleção, o que torna esses trechos O(n^2). Você notará a diferença em qualquer coleção de mais de um punhado de elementos. Eu nunca usaria isso em código real.
Pawan

13

solução de base java 8:

List duplicates =    
list.stream().collect(Collectors.groupingBy(Function.identity()))
    .entrySet()
    .stream()
    .filter(e -> e.getValue().size() > 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

a lista de entrada é transformada em um mapa, (agrupamento pelos mesmos valores). então, os valores do mapa com valor único são "excluídos", em seguida, mapeiam usando a chave, então a lista da lista é transformada em uma Lista
بلال المصمودي

solução bonita e rápida, diretamente modificável para filtrar em getters específicos de item
arberg

11
int[] nums =  new int[] {1, 1, 2, 3, 3, 3};
Arrays.sort(nums);
for (int i = 0; i < nums.length-1; i++) {

    if (nums[i] == nums[i+1]) {
        System.out.println("duplicate item "+nums[i+1]+" at Location"+(i+1) );
    }

}

Obviamente, você pode fazer o que quiser com eles (ou seja, colocar em um Conjunto para obter uma lista exclusiva de valores duplicados) em vez de imprimir ... Isso também tem a vantagem de registrar a localização dos itens duplicados.


7

Usando Guava em Java 8

private Set<Integer> findDuplicates(List<Integer> input) {
    // Linked* preserves insertion order so the returned Sets iteration order is somewhat like the original list
    LinkedHashMultiset<Integer> duplicates = LinkedHashMultiset.create(input);

    // Remove all entries with a count of 1
    duplicates.entrySet().removeIf(entry -> entry.getCount() == 1);

    return duplicates.elementSet();
}

7

Isso também funciona:

public static Set<Integer> findDuplicates(List<Integer> input) {
    List<Integer> copy = new ArrayList<Integer>(input);
    for (Integer value : new HashSet<Integer>(input)) {
        copy.remove(value);
    }
    return new HashSet<Integer>(copy);
}

Funciona, mas é bastante lento, pois chamar remove () em uma lista de array é uma pesquisa linear.
johnstosh de

verdade. Observe que, se sua entrada contiver muitas duplicatas, o impacto de desempenho será menor do que se houver apenas algumas delas.
Adriaan Koster

6

Você pode usar algo assim:

List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
    yourOldList.remove(i);
    if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}

2
Usar List aqui é muito ineficaz
Alexander Farber,

2
E não me deixe começar a usar um inttipo de variável aqui. Isso significa que para cada iteração, um Integer é desempacotado uma vez e um int é embalado quatro vezes!
Sean Patrick Floyd

1
Acho que você pode obter facilmente uma ConcurrentModificationException ao tentar remover um elemento da lista durante a iteração sobre ele
Jad B.

1
isso é 100% ConcurrentModificationException, já que você itera em uma lista e remove elementos rapidamente.
theo231022

5

Lambas pode ser uma solução

Integer[] nums =  new Integer[] {1, 1, 2, 3, 3, 3};
List<Integer> list = Arrays.asList(nums);

List<Integer> dps = list.stream().distinct().filter(entry -> Collections.frequency(list, entry) > 1).collect(Collectors.toList());

1
Funciona, mas executa Collections.frequency para cada entrada e, portanto, é lento.
arberg 05 de

4

Use um MultiMap para armazenar cada valor como um conjunto de chave / valor. Em seguida, itere pelas chaves e encontre aquelas com vários valores.


3

Se você usar Eclipse Collections , isso funcionará:

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectByOccurrences(i -> i > 1).toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

Atualização: a partir das Coleções do Eclipse 9.2, agora você pode usarselectDuplicates

MutableList<Integer> list = Lists.mutable.with(1, 1, 2, 3, 3, 3);
Set<Integer> dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(Sets.mutable.with(1, 3), dupes);

Você também pode usar coleções primitivas para fazer isso:

IntList list = IntLists.mutable.with(1, 1, 2, 3, 3, 3);
IntSet dupes = list.toBag().selectDuplicates().toSet();
Assert.assertEquals(IntSets.mutable.with(1, 3), dupes);

Nota: Eu sou um committer para Eclipse Collections.


2
public class practicese {
       public static void main(String[] args) {   

           List<Integer> listOf = new ArrayList<Integer>();
           listOf.add(3);
           listOf.add(1);
           listOf.add(2);
           listOf.add(3);
           listOf.add(3);
           listOf.add(2);
           listOf.add(1);

           List<Integer> tempList = new ArrayList<Integer>();
           for(Integer obj:listOf){
                if(!tempList.contains(obj)){
                    tempList.add(obj);

                }
            }
            System.out.println(tempList);

    }

}

Gostei dessa resposta, só precisava adicionar um outro para salvar a duplicata em outra lista. obrigado
Tiago Machado

2

Semelhante a algumas respostas aqui, mas se você quiser encontrar duplicatas com base em alguma propriedade:

  public static <T, R> Set<R> findDuplicates(Collection<? extends T> collection, Function<? super T, ? extends R> mapper) {
    Set<R> uniques = new HashSet<>();
    return collection.stream()
        .map(mapper)
        .filter(e -> !uniques.add(e))
        .collect(toSet());
  }

1

crie um Map<Integer,Integer>, itere a lista, se um elemento estiver no mapa, aumente seu valor, caso contrário, adicione-o ao mapa com chave = 1
itere o mapa e adicione às listas todos os elementos com chave> = 2

public static void main(String[] args) {
        List<Integer> list = new LinkedList<Integer>();
        list.add(1);
        list.add(1);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        Map<Integer,Integer> map = new HashMap<Integer, Integer>();
        for (Integer x : list) { 
            Integer val = map.get(x);
            if (val == null) { 
                map.put(x,1);
            } else {
                map.remove(x);
                map.put(x,val+1);
            }
        }
        List<Integer> result = new LinkedList<Integer>();
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > 1) {
                result.add(entry.getKey());
            }
        }
        for (Integer x : result) { 
            System.out.println(x);
        }

    }

Isso é muito bom. É a melhor solução se você precisar saber quantas duplicatas existem. Algumas notas: (1) você não precisa chamar remove () antes de executar put (). (2) Você pode configurar LinkedList a partir de um array em vez de usar chamadas add () repetidas. (3) Quando val! = Null, você pode adicionar imediatamente x ao resultado. O resultado pode ser um conjunto ou uma lista, dependendo se você deseja manter a contagem do número de duplicatas.
johnstosh

1

Versão compacta gerada da resposta principal, também adicionado cheque vazio e tamanho de conjunto pré-alocado:

public static final <T> Set<T> findDuplicates(final List<T> listWhichMayHaveDuplicates) {
    final Set<T> duplicates = new HashSet<>();
    final int listSize = listWhichMayHaveDuplicates.size();
    if (listSize > 0) {
      final Set<T> tempSet = new HashSet<>(listSize);
      for (final T element : listWhichMayHaveDuplicates) {
        if (!tempSet.add(element)) {
          duplicates.add(element);
        }
      }
    }
    return duplicates;
  }

Você precisa do cheque zero? O novo HashSet <> (0) retornará o conjunto vazio sensível?
johnstosh de

@johnstosh este código pode ser simplificado, mas a verificação de zero permite apenas inicializar o tempSetcom listSizequando necessário. Esta é uma pequena otimização, mas eu gosto.
Christophe Roussy de

1

Eu peguei a resposta de Sebastian e adicionei um extrator chave a ela -

    private <U, T> Set<T> findDuplicates(Collection<T> collection, Function<? super T,? extends U> keyExtractor) {
        Map<U, T> uniques = new HashMap<>(); // maps unique keys to corresponding values
        return collection.stream()
            .filter(e -> uniques.put(keyExtractor.apply(e), e) != null)
            .collect(Collectors.toSet());
    }

1

Uma alternativa thread-safe é esta:

/**
 * Returns all duplicates that are in the list as a new {@link Set} thread-safe.
 * <p>
 * Usually the Set will contain only the last duplicate, however the decision
 * what elements are equal depends on the implementation of the {@link List}. An
 * exotic implementation of {@link List} might decide two elements are "equal",
 * in this case multiple duplicates might be returned.
 * 
 * @param <X>  The type of element to compare.
 * @param list The list that contains the elements, never <code>null</code>.
 * @return A set of all duplicates in the list. Returns only the last duplicate.
 */
public <X extends Object> Set<X> findDuplicates(List<X> list) {
    Set<X> dups = new LinkedHashSet<>(list.size());
    synchronized (list) {
        for (X x : list) {
            if (list.indexOf(x) != list.lastIndexOf(x)) {
                dups.add(x);
            }
        }
    }
    return dups;
}

0

Tente isso para encontrar itens duplicados na lista:

ArrayList<String> arrayList1 = new ArrayList<String>(); 

arrayList1.add("A"); 
arrayList1.add("A"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("B"); 
arrayList1.add("C"); 

for (int x=0; x< arrayList1.size(); x++) 
{ 
System.out.println("arrayList1 :"+arrayList1.get(x)); 
} 
Set s=new TreeSet(); 
s.addAll(arrayList1); 
Iterator it=s.iterator(); 
while (it.hasNext()) 
{ 
System.out.println("Set :"+(String)it.next()); 
} 

Sim, ele encontra o conjunto, mas não encontra a lista ou o conjunto dos itens que estão duplicados.
johnstosh de

0

Isso deve funcionar para classificados e não classificados.

public void testFindDuplicates() {

    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(3);
    list.add(3);

    Set<Integer> result = new HashSet<Integer>();
    int currentIndex = 0;
    for (Integer i : list) {
        if (!result.contains(i) && list.subList(currentIndex + 1, list.size()).contains(i)) {
            result.add(i);
        }
        currentIndex++;
    }
    assertEquals(2, result.size());
    assertTrue(result.contains(1));
    assertTrue(result.contains(3));
}

Chamar contains () na subList de ArrayList é caro porque é uma pesquisa linear. Portanto, isso está correto para 10 itens, mas não para 10 milhões.
johnstosh de

0

Este é um problema onde as técnicas funcionais brilham. Por exemplo, a seguinte solução F # é mais clara e menos sujeita a bugs do que a melhor solução Java imperativa (e trabalho diariamente com Java e F #).

[1;1;2;3;3;3] 
|> Seq.countBy id 
|> Seq.choose (fun (key,count) -> if count > 1 then Some(key) else None)

Claro, esta questão é sobre Java. Portanto, minha sugestão é adotar uma biblioteca que traga recursos funcionais para o Java. Por exemplo, isso poderia ser resolvido usando minha própria biblioteca da seguinte maneira (e há várias outras por aí que vale a pena conferir também):

Seq.of(1,1,2,3,3,3)
.groupBy(new Func1<Integer,Integer>() {
    public Integer call(Integer key) {
        return key;
    }
}).filter(new Predicate<Grouping<Integer,Integer>>() {
   public Boolean call(Grouping<Integer, Integer> grouping) {
        return grouping.getGrouping().count() > 1;
   }
}).map(new Func1<Grouping<Integer,Integer>,Integer>() {
    public Integer call(Grouping<Integer, Integer> grouping) {
        return grouping.getKey();
    }
});

E então você vê o quanto o Java ainda é péssimo em programação funcional. Um problema tão simples, tão difícil expressar o que você quer em Java.
froginvasion

0
public class DuplicatesWithOutCollection {

    public static void main(String[] args) {

        int[] arr = new int[] { 2, 3, 4, 6, 6, 8, 10, 10, 10, 11, 12, 12 };

        boolean flag = false;
        int k = 1;
        while (k == 1) {

            arr = removeDuplicate(arr);
            flag = checkDuplicate(arr, flag);
            if (flag) {
                k = 1;
            } else {
                k = 0;
            }

        }

    }

    private static boolean checkDuplicate(int[] arr, boolean flag) {
        int i = 0;

        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                flag = true;

            } else {
                flag = false;
            }
            i++;

        }

        return flag;
    }

    private static int[] removeDuplicate(int[] arr) {

        int i = 0, j = 0;
        int[] temp = new int[arr.length];
        while (i < arr.length - 1) {

            if (arr[i] == arr[i + 1]) {

                temp[j] = arr[i + 1];
                i = i + 2;

            } else {

                temp[j] = arr[i];
                i = i + 1;

                if (i == arr.length - 1) {
                    temp[j + 1] = arr[i + 1];
                    break;
                }

            }
            j++;

        }
        System.out.println();
        return temp;
    }

}

Implementar sem usar classes de Coleção. Mas precisa de pouca melhoria no loop. A ajuda do voluntariado é apreciável. O resultado para acima é semelhante a -> 2 3 4 6 8 10 11 12
Samrat Roy

Para que isso seja executado em menos tempo, você precisa usar uma estrutura de dados baseada em hash para controlar as duplicatas. É por isso que você vê as outras soluções usando HashSet () - ele é integrado ao Java.
johnstosh

@johnstosh Sim, eu sei sobre isso, mas estava pensando em fazer isso sem usar coleções, é por isso que mencionei em meu comentário. Como você pode ver, comentei antes de fevereiro de 2017, [existem técnicas em que você não precisa usar coleções com menor complexidade de tempo] geeksforgeeks.org/… .Eu tentei esse programa sem conhecer as práticas do DS e Algo. Você não precisa me downvote por isso ... de qualquer forma, obrigado.
Samrat Roy de

0
import java.util.Scanner;

public class OnlyDuplicates {
    public static void main(String[] args) {
        System.out.print(" Enter a set of 10 numbers: ");
        int[] numbers = new int[10];
        Scanner input = new Scanner(System.in);
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = input.nextInt();
        }
        numbers = onlyDuplicates(numbers);
        System.out.print(" The numbers are: ");
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + "");
        }
    }

    public static int[] onlyDuplicates(int[] list) {
        boolean flag = true;
        int[] array = new int[0];
        array = add2Array(array, list[0]);
        for (int i = 0; i < list.length; i++) {
            for (int j = 0; j < array.length; j++) {
                if (list[i] == array[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                array = add2Array(array, list[i]);
            }
            flag = true;
        }
        return array;
    }
    // Copy numbers1 to numbers2
    // If the length of numbers2 is less then numbers2, return false
    public static boolean copyArray(int[] source, int[] dest) {
        if (source.length > dest.length) {
            return false;
        }

        for (int i = 0; i < source.length; i++) {
            dest[i] = source[i];
        }
        return true;
    }
    // Increase array size by one and add integer to the end of the array
    public static int[] add2Array(int[] source, int data) {
        int[] dest = new int[source.length + 1];
        copyArray(source, dest);
        dest[source.length] = data;
        return dest;
    }
}

o que eu preciso mudar para que isso retorne as duplicatas?
Brenden

Isso deve ser feito como uma nova pergunta.
willaien

0

Este seria um bom método para encontrar valores duplicados, sem usar Set.

public static <T> List<T> findDuplicates(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();

  for(T s : list)
    if(list.indexOf(s) != list.lastIndexOf(s))
      if(!nonDistinctElements.contains(s))
        nonDistinctElements.add(s);

  return nonDistinctElements;
}

E digamos que você deseja um método que retorna uma lista distinta, ou seja, se você passar uma lista onde os elementos estão ocorrendo mais de uma vez, você obterá uma lista com elementos distintos.

public static <T> void distinctList(List<T> list){

List<T> nonDistinctElements = new ArrayList<>();
for(T s : list)
  if(list.indexOf(s) != list.lastIndexOf(s))
    nonDistinctElements.add(s);

for(T nonDistinctElement : nonDistinctElements)
  if(list.indexOf(nonDistinctElement) != list.lastIndexOf(nonDistinctElement))
    list.remove(nonDistinctElement);
}

0

E a versão que usa o commons-collections CollectionUtils.getCardinalityMapmétodo:

final List<Integer> values = Arrays.asList(1, 1, 2, 3, 3, 3);
final Map<Integer, Integer> cardinalityMap = CollectionUtils.getCardinalityMap(values);
System.out.println(cardinalityMap
            .entrySet()
            .stream().filter(e -> e.getValue() > 1)
            .map(e -> e.getKey())
            .collect(Collectors.toList()));

`` `


0

Que tal este código -

public static void main(String[] args) {

    //Lets say we have a elements in array
    int[] a = {13,65,13,67,88,65,88,23,65,88,92};

    List<Integer> ls1 = new ArrayList<>();
    List<Integer> ls2 = new ArrayList<>();
    Set<Integer> ls3 = new TreeSet<>();

    //Adding each element of the array in the list      
    for(int i=0;i<a.length;i++) {
     {
    ls1.add(a[i]);
    }
    }

    //Iterating each element in the arrary
    for (Integer eachInt : ls1) {

    //If the list2 contains the iterating element, then add that into set<> (as this would be a duplicate element)
        if(ls2.contains(eachInt)) {
            ls3.add(eachInt);
        }
        else {ls2.add(eachInt);}

    }

    System.out.println("Elements in array or ls1"+ls1); 
    System.out.println("Duplicate Elements in Set ls3"+ls3);


}

0

apenas no caso de aqueles que também desejam incluir duplicatas e não duplicatas. basicamente a resposta semelhante à resposta correta, mas em vez de retornar de se não parte, você retorna a outra parte

use este código (mude para o tipo que você precisa)

public Set<String> findDup(List<String> Duplicates){
    Set<String> returning = new HashSet<>();
    Set<String> nonreturning = new HashSet<>();
    Set<String> setup = new HashSet<>();
    for(String i:Duplicates){
        if(!setup.add( i )){
            returning.add( i );
        }else{
            nonreturning.add( i );
        }
    }
    Toast.makeText( context,"hello set"+returning+nonreturning+" size"+nonreturning.size(),Toast.LENGTH_SHORT ).show();
    return nonreturning;
}

0

Método mais genérico como variante de https://stackoverflow.com/a/52296246

    /**
     * Returns a duplicated values found in given collection based on fieldClassifier
     *
     * @param collection given collection of elements
     * @param fieldClassifier field classifier which specifies element to check for duplicates(useful in complex objects).
     * @param <T> Type of element in collection
     * @param <K> Element which will be returned from method in fieldClassifier.
     * @return returns list of values that are duplocated.
     */
    public static <T, K> List<K> lookForDuplicates(List<T> collection, Function<? super T, ? extends K> fieldClassifier) {

        return collection.stream().collect(Collectors.groupingBy(fieldClassifier))
                         .entrySet()
                         .stream()
                         .filter(e -> e.getValue().size() > 1)
                         .map(Map.Entry::getKey)
                         .collect(Collectors.toList());
    }

-1

Se você souber o valor máximo (por exemplo, <10000), você pode sacrificar espaço para velocidade. Não consigo lembrar o nome exato desta técnica.

pseudo-código:

//does not handle case when mem allocation fails 
//probably can be extended to unknown values /larger values .
maybe by sorting first
public List<int> GetDuplicates(int max)
{   
    //allocate and clear memory to 0/false
    bit[] buckets=new bit[max]
    memcpy(buckets,0,max);
    //find duplicates
    List<int> result=new List<int>();
    foreach(int val in List)
    {
        if (buckets[val])
        {
            result.add(value);
        }
        else
        {
            buckets[val]=1;
        }
    }
    return  result
}

Eu acho que você quer "booleano" em vez de "bit"? Você executou seu código antes de postá-lo? Este é um bom começo. Se você der uma olhada em HashSet (), verá que é a implementação de 'baldes' que você deseja.
johnstosh de

-1

Apenas tente isto:

Exemplo se os valores da lista são: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] item duplicado [3, 4].

Collections.sort(list);
        List<Integer> dup = new ArrayList<>();
        for (int i = 0; i < list.size() - 1; i++) {
            if (list.get(i) == list.get(i + 1)) {
                if (!dup.contains(list.get(i + 1))) {
                    dup.add(list.get(i + 1));
                }
            }
        }
        System.out.println("duplicate item " + dup);

Invocar contains () em um ArrayList () é uma operação cara, então você deve considerar usar um Set em vez disso. Você verá outras soluções usando HashSet () ou versões vinculadas dele.
johnstosh de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.