Tamsayı türünde bir Listem var, örneğin:
[1, 1, 2, 3, 3, 3]
Tüm kopyaları döndürmek için bir yöntem istiyorum, örneğin:
[1, 3]
Bunu yapmanın en iyi yolu nedir?
Tamsayı türünde bir Listem var, örneğin:
[1, 1, 2, 3, 3, 3]
Tüm kopyaları döndürmek için bir yöntem istiyorum, örneğin:
[1, 3]
Bunu yapmanın en iyi yolu nedir?
Yanıtlar:
Bir değer zaten var olup olmadığına bakılmaksızın bir mantıksal değer döndürme yöntemi add( Setyoksa doğru, zaten varsa yanlış, bkz . Belgeleri ayarlama ).
Bu nedenle, tüm değerleri yineleyin:
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;
}
for (Integer yourIntGereksiz kutulamayı ve kutudan çıkarmayı önlemek için kullanmanızı öneririm , özellikle de girdiniz zaten Integers içerdiğinden .
HashSetyük faktörünü de göz önünde bulundurmanız gerekirse, örneğin bir başlangıç kapasitesi 100belirlediğinizde, bu sayıda eleman eklemek istediğiniz için, bir sonraki 2 ( 128) kuvvetine yuvarlanır, bu da şu anlama gelir: varsayılan yük faktörü olarak 0.75f, yeniden boyutlandırma eşiği olacaktır 96, bu nedenle, 100öğe eklemeden önce yeniden boyutlandırma yapılacaktır . Neyse ki, yeniden boyutlandırma artık o kadar pahalı değil. Güncel JRE'lerle, yeniden boyutlandırma artık yeniden işlenmez, öğeler yalnızca ilgili bit temelinde iki olası sonuç konumu arasında dağıtılır.
Buna da bir çözüme ihtiyacım vardı. Leifg'in çözümünü kullandım ve genel yaptım.
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;
}
John Strickler'in çözümünü aldım ve JDK8'de sunulan akışlar API'sini kullanmak için yeniden tasarladım:
private <T> Set<T> findDuplicates(Collection<T> collection) {
Set<T> uniques = new HashSet<>();
return collection.stream()
.filter(e -> !uniques.add(e))
.collect(Collectors.toSet());
}
distinct()yöntem de durum bilgilidir . Durum bilgisi olmayan verimli (O (n)) ayrı bir işlem düşünemiyorum.
İşte Java 8 ile Akışları kullanan bir çözüm
// 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<>();
Listenizde bu nesnenin sıklığının birden fazla olup olmadığına bakmanız yeterlidir. Ardından sonucunuzda yalnızca benzersiz öğelere sahip olmak için .distinct () çağırın
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
Collections::frequencyO (n). Bir öğenin sıklığını bulmak için tüm koleksiyonun üzerinden geçmesi gerekir. Ve bunu koleksiyondaki her öğe için bir kez çağırıyoruz, bu da bu parçacıkları oluşturur O(n^2). Bir avuç öğeden daha fazlasını içeren herhangi bir koleksiyondaki farkı fark edeceksiniz. Bunu asla gerçek kodda kullanmam.
java 8 temel çözümü:
List duplicates =
list.stream().collect(Collectors.groupingBy(Function.identity()))
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
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) );
}
}
Açıkçası, yazdırmak yerine onlarla istediğinizi yapabilirsiniz (yani, yinelenen değerlerin benzersiz bir listesini elde etmek için bir Set koyun) ... Bu aynı zamanda yinelenen öğelerin konumunu kaydetme avantajına da sahiptir.
Java 8'de Guava'yı kullanma
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();
}
Bu aynı zamanda çalışır:
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);
}
Bunun gibi bir şey kullanabilirsiniz:
List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
yourOldList.remove(i);
if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}
intburada değişken türü olarak kullanmaya başlama . Bu, her bir yineleme için, bir Tamsayının bir kez kutudan çıkarıldığı ve bir tamsayının dört kez kutulanacağı anlamına gelir!
Lambas bir çözüm olabilir
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());
Eclipse Koleksiyonlarını kullanırsanız , bu çalışacaktır:
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);
Güncelleme: Eclipse Collections 9.2'den itibaren artık kullanabilirsinizselectDuplicates
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);
Bunu başarmak için ilkel koleksiyonları da kullanabilirsiniz:
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);
Not: Eclipse Koleksiyonlarının sorumlusuyum.
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);
}
}
Buradaki bazı yanıtlara benzer, ancak bazı özelliklere göre yinelenenleri bulmak istiyorsanız:
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());
}
Map<Integer,Integer>bir öğe oluşturun , listeyi yineleyin, eğer haritada bir öğe varsa değerini artırın, aksi takdirde anahtar = 1
ile haritaya ekleyin haritayı yineleyin ve> = 2 anahtarıyla tüm öğeleri listelere ekleyin
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);
}
}
En iyi cevabın kompakt, genelleştirilmiş versiyonu, ayrıca boş kontrol ve önceden tahsis edilmiş Set boyutu eklendi:
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;
}
tempSetile başlatmaya izin verir listSize. Bu küçük bir optimizasyon ama hoşuma gitti.
Sebastian'ın cevabını aldım ve buna bir anahtar çıkarıcı ekledim -
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());
}
İş parçacığı açısından güvenli bir alternatif şudur:
/**
* 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;
}
Listede yinelenen öğeleri bulmak için şunu deneyin:
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());
}
Bu, sıralı ve sıralanmamış için çalışmalıdır.
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));
}
Bu, işlevsel tekniklerin parladığı bir sorundur. Örneğin, aşağıdaki F # çözümü, en iyi zorunlu Java çözümünden hem daha net hem de daha az hataya açıktır (ve hem Java hem de F # ile her gün çalışıyorum).
[1;1;2;3;3;3]
|> Seq.countBy id
|> Seq.choose (fun (key,count) -> if count > 1 then Some(key) else None)
Elbette bu soru Java ile ilgili. Bu yüzden benim önerim Java'ya işlevsel özellikler getiren bir kitaplık benimsemek. Örneğin, kendi kütüphanem kullanılarak şu şekilde çözülebilir (ve orada bakmaya değer başka birkaç tane daha var):
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();
}
});
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;
}
}
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;
}
}
Bu, Set kullanmadan Yinelenen değerleri bulmak için iyi bir yöntem olacaktır.
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;
}
Ve diyelim ki, size ayrı bir liste döndüren bir yöntem istiyorsunuz, yani elemanların birden çok kez meydana geldiği bir listeyi geçerseniz, farklı elemanların olduğu bir liste alacaksınız.
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);
}
Ve commons-collections CollectionUtils.getCardinalityMapyöntemi kullanan versiyon :
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()));
`
Peki ya bu kod -
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);
}
hem yinelenen hem de yinelenmeyenleri de dahil etmek isteyenler için. temelde cevap doğru cevaba benzer, ancak bölüm değilse geri dönmek yerine else bölümünü geri verirsiniz
bu kodu kullanın (ihtiyacınız olan türü değiştirin)
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;
}
Https://stackoverflow.com/a/52296246 varyantı olarak daha genel yöntem
/**
* 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());
}
Maksimum değeri biliyorsanız (örneğin <10000), hız için yer feda edebilirsiniz. Bu tekniğin tam adını hatırlayamıyorum.
sözde kod:
//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
}
Sadece şunu dene:
Örnek Liste değerleri: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] yinelenen öğe [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);