วิธีจัดเรียงรายการ <วัตถุ> ตามตัวอักษรโดยใช้ฟิลด์ชื่อวัตถุ


103

ฉันมีรายการวัตถุเช่นList<Object> pฉันต้องการจัดเรียงรายการนี้ตามตัวอักษรโดยใช้ฟิลด์ชื่อวัตถุ วัตถุมี 10 ฟิลด์และฟิลด์ชื่อเป็นหนึ่งในนั้น

if (list.size() > 0) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(final Object object1, final Object object2) {
        return String.compare(object1.getName(), object2.getName());
        }
    } );
}

แต่ไม่มีอะไรเหมือน String.compare .. ?


3
คุณจะได้รับชื่ออย่างไร? - Objectไม่มีชื่อ คุณหมายถึงใช้.toString()?
Matt Fenwick

object1และobject2ต้องเป็นชนิดและฟังก์ชั่นการเปรียบเทียบคือCampaign object1.getName().compareTo(object2.getName())
Bart van Heukelom

คุณผสมList<Object>และComparator<Campaign>. คุณทำอย่างนั้นไม่ได้ ไม่ว่าคุณจะมีList<Object>และComparator<Object>หรือList<Campaign>และComparator<Campaign>
viktor

คำตอบ:


231

จากโค้ดของคุณดูเหมือนว่าคุณComparatorได้กำหนดพารามิเตอร์ด้วยCampaignไฟล์. สิ่งนี้จะใช้ได้กับList<Campaign>ไฟล์. compareToนอกจากนี้วิธีการที่คุณกำลังมองหาอยู่

if (list.size() > 0) {
  Collections.sort(list, new Comparator<Campaign>() {
      @Override
      public int compare(final Campaign object1, final Campaign object2) {
          return object1.getName().compareTo(object2.getName());
      }
  });
}

หรือถ้าคุณใช้ Java 1.8

list
  .stream()
  .sorted((object1, object2) -> object1.getName().compareTo(object2.getName()));

ความคิดเห็นสุดท้าย - ไม่มีประเด็นในการตรวจสอบขนาดรายการ การเรียงลำดับจะทำงานในรายการที่ว่างเปล่า


2
ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุดที่กลั่นทุกอย่างให้เป็นสิ่งที่ OP กำลังมองหา และจากความคิดเห็นฉันคิดว่าเขาต้องการแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ดังนั้นเพียงแค่เปลี่ยนการเปรียบเทียบเพื่อเปรียบเทียบเพื่อเปรียบเทียบกับ
กรณีที่ไม่สนใจ

ปรับปรุงเล็กน้อยในการแก้ปัญหาแรก: เราสามารถทำได้ถ้า (list.size ()> 1) - สำหรับ 1 รายการไม่จำเป็นต้องเรียงลำดับ ..
Rami Yampolsky

12
คุณสามารถใช้ได้Comparator.comparing(Campaign::getName)
Jose Da Silva

4
list.sort((object1, object2) -> object1. getName().compareTo(object2. getName()));ทำงานให้ฉัน
Lucas

1
ลองใช้sortedList = list.stream().sort((object1, object2) -> object1. getName().compareTo(object2. getName()))..collect(Collectors.toList());เพื่อรับรายการที่จัดเรียงใหม่
Lukas

16

วิธีที่ถูกต้องที่สุดในการจัดเรียงสตริงตามตัวอักษรคือการใช้Collatorเนื่องจากความเป็นสากล บางภาษามีลำดับที่แตกต่างกันเนื่องจากมีอักขระพิเศษบางตัวเป็นต้น

   Collator collator = Collator.getInstance(Locale.US);
   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return collator.compare(c1.getName(), c2.getName());
        }
       });
   }

string.compare(otherString)หากคุณไม่สนใจเกี่ยวกับการใช้งานสากล

   if (!list.isEmpty()) {
    Collections.sort(list, new Comparator<Campaign>() {
        @Override
        public int compare(Campaign c1, Campaign c2) {
            //You should ensure that list doesn't contain null values!
            return c1.getName().compare(c2.getName());
        }
       });
   }

11

ดูCollections.sort()และComparatorอินเทอร์เฟซ

การเปรียบเทียบสตริงสามารถทำได้ด้วยobject1.getName().compareTo(object2.getName())หรือobject2.getName().compareTo(object1.getName())(ขึ้นอยู่กับทิศทางการจัดเรียงที่คุณต้องการ)

object1.getName().toUpperCase().compareTo(object2.getName().toUpperCase())หากคุณต้องการเรียงลำดับจะเป็นกรณีไม่เชื่อเรื่องพระเจ้าทำ


และคุณแนะนำให้แยกฟิลด์ที่เรียกnamaจากObjectประเภทอย่างไร คำตอบนี้ยังไม่สมบูรณ์
มิต

การแยกชื่อขึ้นอยู่กับประเภทของวัตถุ ฉันคิดว่ามันเป็นเพียงตัวยึดตำแหน่ง หากคุณไม่สามารถระบุประเภทที่เป็นรูปธรรมมากขึ้นได้คุณอาจต้องใช้การสะท้อนกลับ
tobiasbayer


7
public class ObjectComparator implements Comparator<Object> {

    public int compare(Object obj1, Object obj2) {
        return obj1.getName().compareTo(obj2.getName());
    }

}

โปรดแทนที่ Object ด้วยคลาสของคุณ ซึ่งมีฟิลด์ชื่อ

การใช้งาน:

ObjectComparator comparator = new ObjectComparator();
Collections.sort(list, comparator);

ฉันทำสิ่งนี้ แต่กว่าจะมี "การทดสอบ" ก่อน "Search"
:(

ถ้าคุณต้องการ o ทำการเรียงลำดับแบบย้อนกลับให้แทนที่obj1.getName().compareTo(obj2.getName()ด้วยobj2.getName().compareTo(obj1.getName()ในคลาสตัวเปรียบเทียบ
ม.ค. Vorcak

2

สิ่งที่ต้องการ

  List<FancyObject> theList =  ;
  Collections.sort (theList,
                    new Comparator<FancyObject> ()
                    { int compare (final FancyObject a, final FancyObject d)
                          { return (a.getName().compareTo(d.getName())); }});

2

นี่คือคำตอบของ Robert B รุ่นที่ใช้งานได้List<T>และจัดเรียงตามคุณสมบัติ String ที่ระบุของวัตถุโดยใช้ Reflection และไม่มีไลบรารีของบุคคลที่สาม

/**
 * Sorts a List by the specified String property name of the object.
 * 
 * @param list
 * @param propertyName
 */
public static <T> void sortList(List<T> list, final String propertyName) {

    if (list.size() > 0) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(final T object1, final T object2) {
                String property1 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object1);
                String property2 = (String)ReflectionUtils.getSpecifiedFieldValue (propertyName, object2);
                return property1.compareToIgnoreCase (property2);
            }
        });
    }
}


public static Object getSpecifiedFieldValue (String property, Object obj) {

    Object result = null;

    try {
        Class<?> objectClass = obj.getClass();
        Field objectField = getDeclaredField(property, objectClass);
        if (objectField!=null) {
            objectField.setAccessible(true);
            result = objectField.get(obj);
        }
    } catch (Exception e) {         
    }
    return result;
}

public static Field getDeclaredField(String fieldName, Class<?> type) {

    Field result = null;
    try {
        result = type.getDeclaredField(fieldName);
    } catch (Exception e) {
    }       

    if (result == null) {
        Class<?> superclass = type.getSuperclass();     
        if (superclass != null && !superclass.getName().equals("java.lang.Object")) {       
            return getDeclaredField(fieldName, type.getSuperclass());
        }
    }
    return result;
}

2

คุณสามารถใช้sortThisBy()จากEclipse Collections :

MutableList<Campaign> list = Lists.mutable.empty();
list.sortThisBy(Campaign::getName);

หากคุณไม่สามารถเปลี่ยนประเภทของรายการจากList:

List<Campaign> list = new ArrayList<>();
ListAdapter.adapt(list).sortThisBy(Campaign::getName);

หมายเหตุ: ฉันเป็นผู้สนับสนุน Eclipse Collections


2

ลองสิ่งนี้:

List< Object> myList = x.getName;
myList.sort(Comparator.comparing(Object::getName));

FYI หากคุณกำลังทำสิ่งนี้ใน Android ต้องใช้ API ระดับ 24 เป็นอย่างน้อย
MSpeed

1

หากวัตถุของคุณมีบรรพบุรุษร่วมกัน [ปล่อยให้เป็นT] คุณควรใช้List<T>แทนList<Object>และใช้ตัวเปรียบเทียบสำหรับ T นี้โดยใช้ฟิลด์ชื่อ

หากคุณไม่มีบรรพบุรุษร่วมกันคุณสามารถใช้ Comperator และใช้การสะท้อนเพื่อแยกชื่อได้โปรดทราบว่าไม่ปลอดภัยไม่ได้รับการแนะนำและได้รับผลกระทบจากประสิทธิภาพที่ไม่ดีในการใช้การสะท้อนกลับ แต่ช่วยให้คุณเข้าถึงชื่อฟิลด์ได้ โดยไม่รู้อะไรเกี่ยวกับประเภทที่แท้จริงของวัตถุ [นอกเหนือจากข้อเท็จจริงที่ว่ามันมีฟิลด์ที่มีชื่อที่เกี่ยวข้อง]

ในทั้งสองกรณีคุณควรใช้Collections.sort ()เพื่อจัดเรียง



0

นี้คือสมมติรายการYourClassแทนObjectตามที่อธิบายไว้โดยAmit

คุณสามารถใช้บิตนี้จากห้องสมุด Google Guava:

Collections.sort(list, Ordering.natural()
  .onResultOf(new Function<String,YourClass>() {
  public String call(YourClass o) {
     return o.getName();
  }))
  .nullsLast();

คำตอบอื่น ๆ ที่พูดถึงComparatorไม่ได้ไม่ถูกต้องเนื่องจากการดำเนินการOrdering Comparatorในความคิดของฉันวิธีนี้ง่ายกว่าเล็กน้อยแม้ว่าอาจจะยากกว่าหากคุณเป็นมือใหม่และไม่คุ้นเคยกับการใช้ไลบรารีและ / หรือ "การเขียนโปรแกรมเชิงฟังก์ชัน"

คัดลอกอย่างไร้ยางอายจากคำตอบนี้สำหรับคำถามของฉันเอง


นี่เป็นวิธีที่ฉันทำ แต่อาจจะมากเกินไปสำหรับ OP
Greg Case

0

ใช้การเลือกเรียงลำดับ

for(int i = list.size() - 1; i > 0; i--){

  int max = i

  for(int j = 0; j < i; j++){
      if(list.get(j).getName().compareTo(list.get(j).getName()) > 0){
            max= j;
      }
  }

  //make the swap
  Object temp = list.get(i);
  list.get(i) = list.get(max);
  list.get(max) = temp;

}

(1) ทำไมเขาถึงคิดค้นล้อใหม่? เกิดอะไรขึ้นCollections.sort()? (2) รายการเป็นประเภทList<Object>ดังนั้นlist.get(j).getName()จะไม่รวบรวม (3) โซลูชันนี้คือ O (n ^ 2) ในขณะที่การใช้Collections.sort()เป็นโซลูชัน O (nlogn) ที่ดีกว่า
มิต

0

หากคุณใช้ a List<Object>to hold วัตถุของประเภทย่อยที่มีช่องชื่อ (ให้เรียกประเภทย่อยนั้นNamedObject) คุณจะต้องดาวน์แคสต์องค์ประกอบรายการเพื่อเข้าถึงชื่อ คุณมี 3 ตัวเลือกทางเลือกที่ดีที่สุดคือ

  1. อย่าใช้ a List<Object>ในตอนแรกหากคุณสามารถช่วยได้ - เก็บวัตถุที่มีชื่อของคุณไว้ในไฟล์List<NamedObject>
  2. คัดลอกList<Object>องค์ประกอบของคุณลงในการList<NamedObject>ดาวน์คาสติ้งในกระบวนการทำการจัดเรียงจากนั้นคัดลอกกลับ
  3. ทำการดาวน์คาสติ้งในตัวเปรียบเทียบ

ตัวเลือกที่ 3 จะมีลักษณะดังนี้:

Collections.sort(p, new Comparator<Object> () {
        int compare (final Object a, final Object b) {
                return ((NamedObject) a).getName().compareTo((NamedObject b).getName());
        }
}

0
if(listAxu.size() > 0){
     Collections.sort(listAxu, new Comparator<Situacao>(){
        @Override
        public int compare(Situacao lhs, Situacao rhs) {            
            return lhs.getDescricao().compareTo(rhs.getDescricao());
        }
    });
 }

1
สนใจที่จะอธิบายรายละเอียดมากกว่าการทิ้งโค้ดในคำถามอายุ 3 ปีหรือไม่?
Holloway

0

คำตอบของ @ Victor ใช้ได้ผลกับฉันและรีโพสต์ที่นี่ใน Kotlin เผื่อว่าจะเป็นประโยชน์กับคนอื่นที่ใช้ Android

if (list!!.isNotEmpty()) {
   Collections.sort(
     list,
     Comparator { c1, c2 -> //You should ensure that list doesn't contain null values!
     c1.name!!.compareTo(c2.name!!)
   })
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.