ฉันมีรายการประเภทจำนวนเต็มเช่น:
[1, 1, 2, 3, 3, 3]
ฉันต้องการวิธีการส่งคืนรายการที่ซ้ำกันทั้งหมดเช่น:
[1, 3]
วิธีที่ดีที่สุดในการทำคืออะไร?
ฉันมีรายการประเภทจำนวนเต็มเช่น:
[1, 1, 2, 3, 3, 3]
ฉันต้องการวิธีการส่งคืนรายการที่ซ้ำกันทั้งหมดเช่น:
[1, 3]
วิธีที่ดีที่สุดในการทำคืออะไร?
คำตอบ:
วิธีการadd
ของSet
ผลตอบแทนบูลไม่ว่าจะเป็นค่าที่มีอยู่แล้ว (จริงถ้ามันไม่ได้อยู่ที่เป็นเท็จถ้ามีอยู่แล้วให้ดูเอกสารชุด )
ดังนั้นเพียงแค่วนซ้ำค่าทั้งหมด:
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 yourInt
เพื่อหลีกเลี่ยงการชกมวยและการแกะกล่องโดยไม่จำเป็นโดยเฉพาะอย่างยิ่งเนื่องจากข้อมูลของคุณมีInteger
s อยู่แล้ว
HashSet
คุณต้องพิจารณาโหลดแฟกเตอร์เช่นเมื่อคุณระบุความจุเริ่มต้น100
เนื่องจากคุณต้องการเพิ่มจำนวนองค์ประกอบนั้นจะถูกปัดเศษเป็นกำลังถัดไปของ 2 ( 128
) ซึ่งหมายความว่า ด้วยค่าเริ่มต้นของปัจจัยการโหลด0.75f
เกณฑ์การปรับขนาดจะเป็น96
ดังนั้นจะมีการปรับขนาดก่อนที่คุณจะเพิ่ม100
องค์ประกอบ โชคดีที่การปรับขนาดไม่ได้มีราคาแพงอีกต่อไป ด้วย JRE ที่เป็นปัจจุบันการปรับขนาดจะไม่ได้ทำการรีแฮชอีกต่อไปองค์ประกอบจะได้รับการกระจายระหว่างตำแหน่งผลลัพธ์ที่เป็นไปได้ทั้งสองตามบิตที่เกี่ยวข้อง
ฉันต้องการวิธีแก้ปัญหานี้เช่นกัน ฉันใช้วิธีแก้ปัญหาของ leifg และทำให้เป็นแบบทั่วไป
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 และปรับปรุงใหม่เพื่อใช้สตรีม API ที่แนะนำใน 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());
}
distinct()
นั้นยังเป็นสถานะ ไม่สามารถคิดถึงการดำเนินการที่แตกต่างอย่างมีประสิทธิภาพ (O (n)) ซึ่งไม่ได้ระบุสถานะ
นี่คือวิธีแก้ปัญหาโดยใช้ Streams กับ 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<>();
คุณเพียงแค่ดูว่าความถี่ของวัตถุนี้มากกว่าหนึ่งครั้งในรายการของคุณหรือไม่ จากนั้นเรียก. discinct () เพื่อให้มีเฉพาะองค์ประกอบที่ไม่ซ้ำกันในผลลัพธ์ของคุณ
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::frequency
คือ O (n) ต้องผ่านคอลเลคชันทั้งหมดเพื่อค้นหาความถี่ของไอเท็ม O(n^2)
และเรากำลังเรียกร้องครั้งนี้ครั้งเดียวสำหรับทุกรายการในคอลเลกชันซึ่งจะทำให้ตัวอย่างเหล่านี้ คุณจะสังเกตเห็นความแตกต่างในคอลเลกชันที่มีองค์ประกอบมากกว่าหนึ่งกลุ่ม ฉันไม่เคยใช้สิ่งนี้ในรหัสจริง
โซลูชันฐาน 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());
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) );
}
}
เห็นได้ชัดว่าคุณสามารถทำอะไรก็ได้ที่คุณต้องการ (เช่นใส่ชุดเพื่อรับรายการค่าที่ซ้ำกัน) แทนที่จะพิมพ์ ... นอกจากนี้ยังมีประโยชน์ในการบันทึกตำแหน่งของรายการที่ซ้ำกันด้วย
ใช้ Guava บน 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();
}
สิ่งนี้ยังใช้งานได้:
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);
}
คุณสามารถใช้สิ่งนี้:
List<Integer> newList = new ArrayList<Integer>();
for(int i : yourOldList)
{
yourOldList.remove(i);
if(yourOldList.contains(i) && !newList.contains(i)) newList.add(i);
}
int
เป็นประเภทตัวแปรที่นี่ หมายความว่าสำหรับการวนซ้ำทุก ๆ ครั้งจำนวนเต็มจะถูกแกะกล่องหนึ่งครั้งและ int จะถูกใส่กล่องสี่ครั้ง!
Lambas อาจเป็นทางออก
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());
ใช้ MultiMap เพื่อจัดเก็บแต่ละค่าเป็นชุดคีย์ / ค่า จากนั้นทำซ้ำตามคีย์และค้นหาคีย์ที่มีหลายค่า
หากคุณใช้Eclipse Collectionsสิ่งนี้จะได้ผล:
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);
อัปเดต:ณ Eclipse Collections 9.2 คุณสามารถใช้งานได้แล้วselectDuplicates
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);
คุณยังสามารถใช้คอลเลกชันดั้งเดิมเพื่อทำสิ่งนี้ให้สำเร็จ:
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);
หมายเหตุ:ฉันเป็นผู้กำหนดค่า Eclipse Collections
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);
}
}
คล้ายกับคำตอบบางส่วนที่นี่ แต่ถ้าคุณต้องการค้นหารายการที่ซ้ำกันตามคุณสมบัติบางอย่าง:
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>
รายการวนซ้ำหากองค์ประกอบอยู่ในแผนที่เพิ่มค่าหรือเพิ่มลงในแผนที่โดยใช้ key = 1 วน
ซ้ำแผนที่และเพิ่มรายการองค์ประกอบทั้งหมดด้วยคีย์> = 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);
}
}
คำตอบยอดนิยมในเวอร์ชันที่ได้รับการยืนยันขนาดกะทัดรัดนอกจากนี้ยังเพิ่มการตรวจสอบว่างและขนาดชุดที่จัดสรรไว้ล่วงหน้า:
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;
}
tempSet
ด้วยlistSize
เมื่อจำเป็นเท่านั้น นี่เป็นการเพิ่มประสิทธิภาพเล็กน้อย แต่ฉันชอบ
ฉันรับคำตอบของเซบาสเตียนและเพิ่ม keyExtractor เข้าไป -
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());
}
ทางเลือกที่ปลอดภัยต่อเธรดคือ:
/**
* 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;
}
ลองทำเช่นนี้เพื่อค้นหารายการที่ซ้ำกันในรายการ:
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());
}
สิ่งนี้ควรใช้ได้กับการจัดเรียงและไม่เรียงลำดับ
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));
}
นี่เป็นปัญหาที่เทคนิคการใช้งานมีความโดดเด่น ตัวอย่างเช่นโซลูชัน F # ต่อไปนี้มีทั้งความชัดเจนและข้อผิดพลาดน้อยกว่าโซลูชัน Java ที่จำเป็นที่ดีที่สุด (และฉันทำงานทุกวันกับทั้ง Java และ F #)
[1;1;2;3;3;3]
|> Seq.countBy id
|> Seq.choose (fun (key,count) -> if count > 1 then Some(key) else None)
แน่นอนคำถามนี้เกี่ยวกับ Java ดังนั้นคำแนะนำของฉันคือใช้ไลบรารีที่นำคุณสมบัติการทำงานมาสู่ Java ตัวอย่างเช่นสามารถแก้ไขได้โดยใช้ไลบรารีของฉันเองดังต่อไปนี้ (และมีอีกหลายอย่างที่ควรค่าแก่การดูด้วย):
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;
}
}
นี่เป็นวิธีที่ดีในการค้นหาค่าที่ซ้ำกันโดยไม่ต้องใช้ 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;
}
และบอกว่าคุณต้องการวิธีที่ส่งคืนรายการที่แตกต่างกันเช่นหากคุณส่งรายการที่มีองค์ประกอบเกิดขึ้นมากกว่าหนึ่งครั้งคุณจะได้รับรายการที่มีองค์ประกอบที่แตกต่างกัน
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);
}
และเวอร์ชันที่ใช้commons-collections
CollectionUtils.getCardinalityMap
วิธีการ:
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()));
`` `
รหัสนี้เป็นอย่างไร -
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);
}
ในกรณีที่ต้องการรวมทั้งรายการที่ซ้ำกันและไม่ซ้ำกัน โดยพื้นฐานแล้วคำตอบจะคล้ายกับคำตอบที่ถูกต้อง แต่แทนที่จะกลับจากถ้าไม่ใช่ส่วนหนึ่งคุณจะกลับส่วนอื่น
ใช้รหัสนี้ (เปลี่ยนเป็นประเภทที่คุณต้องการ)
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
/**
* 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());
}
หากคุณทราบค่าสูงสุด (เช่น <10,000) คุณสามารถสละพื้นที่เพื่อความเร็วได้ ฉันจำชื่อที่แน่นอนของเทคนิคนี้ไม่ได้
รหัสหลอก:
//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
}
ลองทำสิ่งนี้:
ตัวอย่างถ้าค่ารายการคือ: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] รายการที่ซ้ำกัน [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);