2012-02-06 27 views
8

Tôi có danh sách List<Custom> nơi Custom là nhưsố Tính của mục có tài sản

class Custom{ 
    public int id; 
    public String name; 
} 

Làm thế nào để có được số hạng mục có tên "Tom"? Có cách nào dễ dàng hơn một vòng lặp for?

+0

Không có 'LINQ' cho Java, mặc dù có điều này ... http://stackoverflow.com/questions/346721/linq-for-java-tool – xandercoded

Trả lời

2

Không có giải pháp dễ dàng hơn với các bộ sưu tập tiêu chuẩn. Bạn phải lặp qua danh sách và đếm số lần xuất hiện của tên.

1

Hoặc bạn theo dõi khi bạn thêm hoặc xóa các mục khỏi danh sách. Điều này có thể thay thế cho một Hashmap Name-> Count. Khi bạn thêm một mục, bạn tăng số lượng cho tên đó và khi bạn xóa nó, bạn sẽ giảm số lượng.

Hoặc bạn lặp lại bộ sưu tập bằng kiểm tra vòng lặp cho tên được đề cập.

Tùy thuộc vào hành vi ứng dụng của bạn, một trong những phương pháp này sẽ nhanh hơn nhưng không có thêm thông tin thì khó mà biết được.

1

Có thể dễ dàng hơn. Bây giờ, bạn có thể lưu trữ các đối tượng của mình trong một chuỗi Bản đồ <, Danh sách < Tùy chỉnh > > thay thế nơi khóa là tên. Để có được số lượng các mục nơi tên == "Tom" bạn có thể sau đó chỉ cần làm:

List<Custom> l = myMap.get("Tom"); 
int count = 0; 
if (l != null) { 
    count = l.size(); 
} 
1

Bạn cũng có thể sắp xếp danh sách trước khi vòng lặp, sau đó sử dụng chia-và-chinh phục để tìm trận đấu, sau đó đếm. Nó thực sự phụ thuộc vào nhu cầu của bạn, như bao nhiêu yếu tố? Có nhiều lần chèn sau khi tìm kiếm không? vv

1

Cách thức được xác định bây giờ sẽ luôn yêu cầu lặp qua danh sách.

Tạo chỉ mục phụ với bản đồ tên để danh sách id là một ý tưởng hay.

Một tùy chọn khác sẽ là đảm bảo danh sách được sắp xếp theo tên, trong trường hợp đó tất cả "Tom" sẽ được lưu trữ cạnh nhau. Sau đó, bạn có thể tìm thấy nắm đấm "Tom" trong thời gian O (log (n)) với tìm kiếm nhị phân và chỉ cần đếm từ đó cho đến khi bạn đạt đến "không phải" Tom hoặc cuối danh sách. Thao tác chèn sẽ có độ phức tạp O (n) khi bạn cần di chuyển tất cả các phần tử sau vị trí chèn bởi một vị trí, vì vậy hãy xem xét cẩn thận :-)

4

Cá nhân tôi thích sử dụng Apache Commons Collection lib khi có thể. (Nhưng cái trên sourceforge vì nó sử dụng Generics) Nó cho phép bạn thực hiện một số thứ khá tao nhã như lập bản đồ danh sách hoặc danh sách lọc (theo cách sắp xếp-ish). Bạn sẽ kết thúc bằng cách viết một cái gì đó như thế này:

int count = CollectionUtils.countMatches(myList, new Predicate<Custom>(){ 
    public boolean evaluate(Custom c){ return "Tom".equals(c.name); } 
} 

Nhược điểm duy nhất là vì Java không có chức năng thứ tự đầu tiên, bạn phải viết ít đối tượng như trường hợp Predicate. Nó sẽ sạch hơn nếu bạn có thể viết các hàm ẩn danh. tức là trong scala, nó sẽ là thế này:

val myList = List("a", "a", "b", "c", "a") 
val c = myList.count{ "a".equals(_) } // is 3 
5

Nếu bạn đang đi để lọc theo tên ở một số nơi, đặc biệt là nếu bạn đang đi để chuỗi bộ lọc với những người khác xác định tại thời gian chạy, Google Guava vị có thể giúp bạn:

public static Predicate<Custom> nameIs(final String name) { 
    return new Predicate<Custom>() { 
     @Override public boolean apply(Custom t) { 
      return t.name.equals(name); 
     } 
    }; 
} 

Khi bạn đã mã hóa vị từ đó, việc lọc và tính sẽ chỉ có một dòng mã.

int size = Collections2.filter(customList, nameIs("Tom")).size(); 

Như bạn có thể thấy, việc xây dựng tiết của một vị (phong cách chức năng) sẽ không phải luôn luôn dễ đọc hơn, nhanh hơn hoặc giúp bạn tiết kiệm dòng mã so với các vòng (phong cách bắt buộc). Trên thực tế, Guava documentation tuyên bố rõ ràng rằng kiểu bắt buộc phải được sử dụng theo mặc định. Nhưng các vị từ là một công cụ tốt đẹp để có anyway.

0

Điều này thì sao? :

package test; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Map; 

public class CustomArrayBuilder extends ArrayList<Custom> { 

    Map<String, Integer> namesMap = new HashMap<String, Integer>(); 

    public CustomArrayBuilder(Collection<? extends Custom> c) { 
     super(c); 
     this.prepareAddAll(c); 
    } 

    public int getDifferentNamesAmount() { 
     return this.namesMap.size(); 
    } 

    public int getNameAmount(String name) { 
     Integer integer = this.namesMap.get(name); 
     return (integer != null) ? integer : 0; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Custom set(int index, Custom element) { 
     Custom custom = super.set(index, element); 
     prepareSet(custom, element); 
     return custom; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean add(Custom e) { 
     this.prepareAdd(e); 
     return super.add(e); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void add(int index, Custom element) { 
     this.prepareAdd(element); 
     super.add(index, element); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Custom remove(int index) { 
     Custom custom = super.remove(index); 
     this.prepareRemove(custom); 
     return custom; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void clear() { 
     super.clear(); 
     this.namesMap.clear(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean addAll(Collection<? extends Custom> c) { 
     this.prepareAddAll(c); 
     return super.addAll(c); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean addAll(int index, Collection<? extends Custom> c) { 
     this.prepareAddAll(c); 
     return super.addAll(index, c); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean remove(Object o) { 
     if (super.remove(o)) { 
      this.prepareRemove((Custom) o); 
      return true; 
     } else { 
      return false; 
     } 
    } 

    private void prepareSet(Custom oldCustom, Custom newCustom) { 
     if (oldCustom != null && !oldCustom.name.equals(newCustom.name)) { 
      this.prepareRemove(oldCustom); 
      this.prepareAdd(newCustom); 
     } 
    } 

    private void prepareAdd(Custom custom) { 
     if (custom != null) { 
      Integer integer = this.namesMap.get(custom.name); 
      this.namesMap.put(custom.name, (integer != null) ? integer + 1 : 1); 
     } 
    } 

    private void prepareAddAll(Collection<? extends Custom> c) { 
     for (Custom custom : c) { 
      this.prepareAdd(custom); 
     } 
    } 

    private void prepareRemove(Custom custom) { 
     if (custom != null) { 
      Integer integer = this.namesMap.get(custom.name); 
      this.namesMap.put(custom.name, (integer != null && integer > 0) ? integer - 1 : 0); 
     } 
    } 
} 

Cách sử dụng:

package test; 

import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    public static void main(String[] args) { 

     List<Custom> list = new ArrayList<Custom>() {{ 
      add(new Custom("A")); 
      add(new Custom("B")); 
      add(new Custom("C")); 
      add(new Custom("A")); 
      add(new Custom("A")); 
      add(new Custom("B")); 
     }}; 

     CustomArrayBuilder customs = new CustomArrayBuilder(list); 
     Custom custom = new Custom("B"); 
     customs.add(custom); 
     customs.add(custom); 
     customs.remove(custom); 
     customs.remove(custom); 
     customs.remove(custom); 

     System.out.println("A: " + customs.getNameAmount("A")); 
     System.out.println("B: " + customs.getNameAmount("B")); 
     System.out.println("C: " + customs.getNameAmount("C")); 
     System.out.println("Z: " + customs.getNameAmount("Z")); 
     System.out.println("Total different names: " + customs.getDifferentNamesAmount()); 
    } 
} 

Output:

A: 3 
B: 2 
C: 1 
Z: 0 
Total different names: 3 

Nó có thể là hữu ích khi bạn thường sử dụng các hoạt động đếm của bạn. Lưu ý: Bạn không nên thay đổi tên của đối tượng tùy chỉnh, nó phải là cuối cùng:

package test; 

class Custom { 
    public int id; 
    final public String name; 

    public Custom(String name) { 
     this.name = name; 
    } 
} 

Hoặc bạn phải làm điều gì đó với danh sách quá, khi bạn đang thay đổi tên của một số đối tượng Custom từ danh sách.

7

Điều này có thể được thực hiện dễ dàng với các luồng Java 8 — không yêu cầu thêm thư viện.

List<Custom> list = /*...*/; 
long numMatches = list.stream() 
         .filter(c -> "Tom".equals(c.name)) 
         .count(); 
+0

Cần lưu ý rằng giá trị sau c -> là luôn luôn là một boolean – galv

0

Bạn có thể sử dụng count() từ Eclipse Collections.

MutableList<Custom> customList = Lists.mutable.empty(); 
int count = customList.count(each -> "Tom".equals(each.getName())); 

Nếu bạn không thể thay đổi customList từ List:

List<Custom> customList = new ArrayList<>(); 
int count = ListAdapter.adapt(customList).count(each -> "Tom".equals(each.getName())); 

Nếu bạn có một phương pháp mà kiểm tra cho một tên bạn cũng có thể sử dụng countWith():

MutableList<Custom> customList = Lists.mutable.empty(); 
int count = customList.countWith(Custom::isNamed, "Tom"); 

class Custom 
{ 
    public int id; 
    public String name; 

    public boolean isNamed(String nameToCheck) 
    { 
     return nameToCheck.equals(this.name); 
    } 
} 

Lưu ý: Tôi là một cộng tác viên cho Bộ sưu tập Eclipse.

Các vấn đề liên quan