Xác định các bản sao trong Danh sách


117

Tôi có một Danh sách kiểu Integer, vd:

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

Tôi muốn một phương thức trả về tất cả các bản sao, ví dụ:

[1, 3]

Cách tốt nhất để làm việc này là gì?


2
Danh sách đầu vào có đảm bảo được sắp xếp (như trong ví dụ của bạn) không?
NPE

7
sắp xếp danh sách, sau đó đi bộ, giữ các giá trị hiện tại và trước đó. nếu hiện tại == trước khi bạn có một bản sao.
mcfinnigan

Không, danh sách không nhất thiết phải được sắp xếp.
tươi nhất

Câu trả lời:


183

Phương pháp addcủa Setlợi nhuận một boolean liệu một giá trị đã tồn tại (true nếu nó không tồn tại, false nếu nó đã tồn tại, xem Set tài liệu ).

Vì vậy, chỉ cần lặp qua tất cả các giá trị:

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
Tại sao bạn có setToReturn? Bạn có thể không chỉ sử dụng set1.add (yourInt) và trả về set1 không?
Phil

3
đúng chính xác. Nhưng khi một elemnt chỉ xuất hiện một lần trong danh sách đã chỉ định, phần tử cũng được thêm vào. Nhìn vào ví dụ trong câu hỏi: Giải pháp của tôi sẽ trả về [1,3] khi số 2 được chèn vào set1 nhưng không phải trong setToReturn. Giải pháp của bạn sẽ trả về [1,2,3] (không phải là yêu cầu)
leifg

1
Tôi khuyên bạn nên sử dụng for (Integer yourInt, để tránh đấm bốc và bỏ hộp không cần thiết, đặc biệt vì đầu vào của bạn đã chứa Integers.
Hosam Aly

1
@JonasThelemann toàn bộ ý tưởng của một bộ là nó KHÔNG thể chứa các bản sao. do đó: cho dù bạn có thường xuyên thêm 3 lần thì nó vẫn luôn kết thúc chỉ một lần.
leifg

1
Nhân tiện, trong trường hợp HashSetbạn cũng phải xem xét hệ số tải, ví dụ: khi bạn chỉ định công suất ban đầu là 100, vì bạn muốn thêm số phần tử đó, nó sẽ được làm tròn thành lũy thừa 2 ( 128), hàm ý rằng với hệ số tải mặc định là 0.75f, ngưỡng thay đổi kích thước sẽ là 96, do đó sẽ có thay đổi kích thước trước khi bạn thêm 100các yếu tố. Rất may, thay đổi kích thước không còn đắt nữa. Với các JRE cập nhật, thay đổi kích thước sẽ không được thử lại nữa, các phần tử chỉ được phân phối giữa hai vị trí kết quả có thể có của chúng dựa trên bit có liên quan.
Holger

50

Tôi cần một giải pháp cho điều này là tốt. Tôi đã sử dụng giải pháp của leifg và làm cho nó chung chung.

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
Tôi biết điều này là 3 năm sau, nhưng tại sao một LinkedHashset, tức là tại sao bạn quan tâm đến đơn hàng?
Ahmad ragab

4
@AhmadRagab bạn đúng, LinkedHashset không bắt buộc trừ khi bạn quan tâm đến thứ tự các bản sao được tìm thấy (mà tôi nghĩ rằng tôi đã làm vào thời điểm đó)
John Strickler

Cảm ơn đã theo dõi!
Ahmad Ragab 20/2/2016

Nếu bạn có quá nhiều dữ liệu đầu vào mà bạn muốn sử dụng giải pháp tối ưu này (thay vì sắp xếp đầu vào) thì bạn cũng sẽ muốn phân bổ trước kích thước của các đối tượng Hashset (). Nếu không có sự phân bổ, bạn sẽ không có thời gian chèn O (1) khi chèn vào Hashset (). Điều này là do mảng băm nội bộ được thay đổi kích thước nhiều lần. Các chèn sau đó trung bình đến một cái gì đó như thời gian O (log N). Điều này có nghĩa là xử lý tất cả N mục trở thành O (N log N) khi nó có thể là O (N).
johnstosh

38

Tôi đã lấy giải pháp của John Strickler và làm lại nó để sử dụng API luồng được giới thiệu trong 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
Đây là loại khó đọc, phải không? Bạn đang thực hiện một tác dụng phụ trong hoạt động truyền phát, khiến cho việc lập luận trở nên khó khăn. Nhưng đó chỉ là tôi nghĩ về phong cách chức năng. Nó ngắn gọn và có lẽ là con đường ngắn nhất;).
froginvasion

Đối với danh sách lớn, bạn có thể thực hiện điều này song song trên nhiều luồng?
johnstosh

@froginvasion distinct()phương thức dựng sẵn cũng có trạng thái. Không thể nghĩ ra một hoạt động riêng biệt hiệu quả (O (n)) không trạng thái.
wilmol

18

Đây là một giải pháp sử dụng Luồng với 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<>();

Bạn chỉ cần xem tần số của đối tượng này nhiều hơn một lần trong danh sách của bạn. Sau đó gọi .distotype () để chỉ có các phần tử duy nhất trong kết quả của bạ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

1
Điều này là tốt về khả năng đọc, nhưng nó thực sự xấu cho hiệu suất. Collections::frequencylà O (n). Nó cần phải đi qua toàn bộ bộ sưu tập để tìm tần số của một mặt hàng. Và chúng tôi gọi điều này một lần cho mỗi mục trong bộ sưu tập, điều này tạo nên những đoạn trích này O(n^2). Bạn sẽ nhận thấy sự khác biệt trong bất kỳ bộ sưu tập nào hơn một số yếu tố. Tôi sẽ không bao giờ sử dụng điều này trong mã thực tế.
Pawan

12

giải pháp cơ sở 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());

danh sách đầu vào được định dạng theo bản đồ, (nhóm theo các giá trị tương tự). sau đó các giá trị của bản đồ với giá trị duy nhất được "xóa" rồi sử dụng bản đồ bằng cách sử dụng khóa, sau đó danh sách danh sách được chuyển đổi thành Danh sách
بلال المصمودي

giải pháp đẹp và nhanh chóng, có thể sửa đổi trực tiếp thành lọc trên các getters cụ thể của vật phẩm
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) );
    }

}

Rõ ràng bạn có thể làm bất cứ điều gì bạn muốn với chúng (ví dụ: đặt vào Set để nhận danh sách giá trị trùng lặp duy nhất) thay vì in ... Điều này cũng có lợi ích là ghi lại vị trí của các mục trùng lặp.


7

Sử dụng ổi trên 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

Điều này cũng hoạt động:

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);
}

Nó hoạt động, nhưng nó khá chậm vì việc gọi remove () trong danh sách mảng là tìm kiếm tuyến tính.
johnstosh

thật. Lưu ý rằng nếu đầu vào của bạn chứa nhiều bản sao thì hiệu năng đạt được ít hơn nếu chỉ có một vài trong số chúng.
Adriaan Koster

6

Bạn có thể sử dụng một cái gì đó như thế này:

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

2
Sử dụng Danh sách ở đây rất không hiệu quả
Alexander Farber

2
Và đừng để tôi bắt đầu sử dụng intnhư loại biến ở đây. Điều đó có nghĩa là với mỗi lần lặp duy nhất, một Integer được bỏ hộp một lần và một int được đóng hộp bốn lần!
Sean Patrick Floyd

1
Tôi nghĩ rằng bạn có thể dễ dàng nhận được một concExModificationException khi cố gắng xóa một phần tử khỏi danh sách trong khi lặp lại nó
Jad B.

1
đây là 100% concurrencyModificationException kể từ khi bạn lặp qua một danh sách và bạn loại bỏ các yếu tố một cách nhanh chóng.
theo231022

5

Lambas có thể là một giải pháp

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
Hoạt động, nhưng nó chạy Collections.frequency cho mỗi mục và do đó chậm.
arberg

4

Sử dụng MultiMap để lưu trữ từng giá trị dưới dạng tập hợp khóa / giá trị. Sau đó lặp qua các phím và tìm những cái có nhiều giá trị.


3

Nếu bạn sử dụng Bộ sưu tập Eclipse , điều này sẽ hoạt động:

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);

Cập nhật: Kể từ Bộ sưu tập Eclipse 9.2, bây giờ bạn có thể sử dụngselectDuplicates

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);

Bạn cũng có thể sử dụng các bộ sưu tập nguyên thủy để thực hiện điều này:

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);

Ghi chú: Tôi là người đi làm cho Bộ sưu tập Eclipse.


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);

    }

}

Tôi thích câu trả lời này, chỉ cần thêm một cái khác để lưu bản sao trong danh sách khác. cảm ơn
Tiago Machado

2

Tương tự như một số câu trả lời ở đây, nhưng nếu bạn muốn tìm các bản sao dựa trên một số thuộc tính:

  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

tạo a Map<Integer,Integer>, lặp lại danh sách, nếu một yếu tố có trong bản đồ, hãy tăng giá trị của nó, nếu không hãy thêm nó vào bản đồ với key = 1
lặp lại bản đồ và thêm vào danh sách tất cả các yếu tố có khóa> = 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);
        }

    }

Điều này là khá tốt. Đó là giải pháp tốt nhất nếu bạn cần biết có bao nhiêu bản sao. Một số lưu ý: (1) bạn không cần gọi remove () trước khi thực hiện put (). (2) Bạn có thể thiết lập LinkedList từ một mảng thay vì sử dụng các lệnh gọi add () lặp đi lặp lại. (3) Khi val! = Null, bạn có thể thêm x vào kết quả ngay lập tức. Kết quả có thể là một tập hợp hoặc một danh sách tùy thuộc vào việc bạn muốn giữ số lượng trùng lặp.
johnstosh

1

Phiên bản nhỏ gọn của câu trả lời hàng đầu, cũng được thêm kiểm tra trống và kích thước cài đặt sẵn:

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;
  }

Bạn có cần kiểm tra không? Hashset mới <> (0) sẽ trả về tập hợp trống hợp lý?
johnstosh

@johnstosh mã này có thể được đơn giản hóa, nhưng kiểm tra không cho phép chỉ init tempSetvới listSizekhi cần thiết. Đây là một tối ưu hóa nhỏ nhưng tôi thích nó.
Barshe Roussy

1

Tôi lấy câu trả lời của Sebastian và thêm keyExtractor vào nó -

    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

Một thay thế an toàn chủ đề là đây:

/**
 * 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

Hãy thử điều này để tìm các mục trùng lặp trong danh sách:

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()); 
} 

Có, điều này tìm thấy tập hợp, nhưng nó không tìm thấy danh sách hoặc tập hợp các mục đó là trùng lặp.
johnstosh

0

Điều này sẽ làm việc để sắp xếp và chưa sắp xếp.

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));
}

Việc gọi chứa () trên danh sách con của ArrayList rất tốn kém vì đây là một tìm kiếm tuyến tính. Vì vậy, điều này là ổn cho 10 mặt hàng, nhưng không phải cho 10 triệu.
johnstosh

0

Đây là một vấn đề mà các kỹ thuật chức năng tỏa sáng. Ví dụ, giải pháp F # sau đây rõ ràng hơn và ít bị lỗi hơn so với giải pháp Java bắt buộc tốt nhất (và tôi làm việc hàng ngày với cả Java và F #).

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

Tất nhiên, câu hỏi này là về Java. Vì vậy, đề nghị của tôi là chấp nhận một thư viện mang các tính năng chức năng cho Java. Ví dụ, nó có thể được giải quyết bằng thư viện của riêng tôi như sau (và có một số cái khác ngoài đó cũng đáng xem):

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();
    }
});

Và sau đó bạn thấy Java thực sự vẫn còn tệ như thế nào khi lập trình chức năng. Một vấn đề đơn giản như vậy, thật khó để diễn đạt những gì bạn muốn trong 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;
    }

}

Triển khai mà không sử dụng các lớp Bộ sưu tập. Nhưng cần cải thiện rất ít trong vòng lặp. Trợ giúp tự do là đáng tin cậy. Thông số cho hình trên giống như -> 2 3 4 6 8 10 11 12
Samrat Roy

Để thực hiện việc này trong một khoảng thời gian nhỏ hơn, bạn cần sử dụng cấu trúc dữ liệu dựa trên hàm băm để theo dõi các bản sao. Đó là lý do tại sao bạn thấy các giải pháp khác sử dụng Hashset () - nó được tích hợp vào Java.
johnstosh

@johnstosh Có tôi biết về điều đó nhưng tôi đã suy nghĩ để tạo ra nó mà không sử dụng Bộ sưu tập đó là lý do tại sao tôi đã đề cập trong nhận xét của mình. với độ phức tạp thời gian ít hơn] geekforgeek.org/. Tôi đã thử chương trình đó mà không biết các thực hành DS & Algo. Bạn không cần phải đánh giá thấp tôi về điều đó..tất cả cảm ơn.
Samrat Roy

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;
    }
}

Tôi cần thay đổi điều gì để trả lại các bản sao?
Brenden

Điều này nên được hỏi như một câu hỏi mới.
willaien

0

Đây sẽ là một phương pháp tốt để tìm các giá trị trùng lặp mà không cần sử dụng 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;
}

Và giả sử, bạn muốn một phương thức trả về cho bạn một danh sách riêng, tức là nếu bạn vượt qua một danh sách nơi các phần tử xuất hiện nhiều lần, bạn sẽ nhận được một danh sách có các phần tử riêng biệt.

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

Và phiên bản sử dụng commons-collections CollectionUtils.getCardinalityMapphương thức:

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

Làm thế nào về mã này -

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

chỉ trong trường hợp cho những người cũng muốn bao gồm cả trùng lặp và không trùng lặp. về cơ bản câu trả lời giống với câu trả lời đúng nhưng thay vì trả về từ nếu không phải là phần bạn trả lại phần khác

sử dụng mã này (thay đổi loại bạn cần)

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

Phương pháp chung hơn là biến thể của 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

Nếu bạn biết giá trị tối đa (ví dụ <10000), bạn có thể hy sinh không gian cho tốc độ. Tôi không thể nhớ chính xác tên của kỹ thuật này.

mã giả:

//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
}

Tôi nghĩ bạn muốn "boolean" thay vì "bit"? Bạn đã thực thi mã của mình trước khi đăng nó? Đây là một khởi đầu tốt. Nếu bạn xem Hashset () thì bạn sẽ thấy đó là cách triển khai 'xô' mà bạn mong muốn.
johnstosh

-1

Hãy thử điều này:

Ví dụ nếu giá trị Danh sách là: [1, 2, 3, 4, 5, 6, 4, 3, 7, 8] mục trùng lặp [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);

Gọi chứa () trên một ArrayList () là một hoạt động đắt tiền, vì vậy bạn nên xem xét sử dụng Set thay thế. Bạn sẽ thấy các giải pháp khác bằng cách sử dụng Hashset () hoặc các phiên bản được liên kết của nó.
johnstosh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.