【问题标题】:In Java how do you sort one list based on another?在 Java 中,如何根据另一个列表对一个列表进行排序?
【发布时间】:2013-08-10 09:20:24
【问题描述】:

我已经看到其他几个与此类似的问题,但我还没有真正找到任何可以解决我的问题的问题。

我的用例是这样的:用户最初有一个项目列表(listA)。他们重新排序项目并希望保留该订单(listB),但是,由于限制,我无法在后端保留订单,因此我必须在检索后对 listA 进行排序。

所以基本上,我有 2 个 ArrayList(listA 和 listB)。一个具有列表的特定顺序(listB),另一个具有项目列表(listA)。我想根据 listB 对 listA 进行排序。

【问题讨论】:

  • 当您说您无法在“后端”保留订单时,您是什么意思?如果您能提供预期输入和输出的示例,将会很有帮助。
  • 你的列表有相同的元素吗?
  • @Debacle:请澄清两件事:1)listA和listB之间是否存在1:1的对应关系? 2) listA 和 listB 是否包含对相同对象的引用,还是仅包含与 equals() 等效的对象?
  • 我会重新表述这个问题,但我不知道实际要求的是什么......更好的示例数据也会很有帮助。
  • @Debacle 在 listA 的后端允许哪些操作?我的意思是 swapItems(), removeItem(), addItem(), setItem() ??

标签: java list sorting arraylist


【解决方案1】:
List<String> listA;
Comparator<B> comparator = Comparator.comparing(e -> listA.indexOf(e.getValue()));
//call your comparator inside your list to be sorted
listB.stream().sorted(comparator)..

【讨论】:

    【解决方案2】:

    所以对我来说,要求是将originalListorderedList 进行排序。 originalList 总是包含来自orderedList 的所有元素,但反之则不然。没有新元素。

    fun <T> List<T>.sort(orderedList: List<T>): List<T> {
        return if (size == orderedList.size) {
            orderedList
        } else {
            var keepIndexCount = 0
            mapIndexed { index, item ->
                if (orderedList.contains(item)) {
                    orderedList[index - keepIndexCount]
                } else {
                    keepIndexCount++
                    item
                }
        }
    }}
    

    附:我的情况是我有列表,用户可以通过拖放进行排序,但有些项目可能会被过滤掉,所以我们保留隐藏项目的位置。

    【讨论】:

      【解决方案3】:

      这是一个将时间复杂度增加2n 的解决方案,但可以实现您想要的。它也不关心您要排序的 List R 是否包含 Comparable 元素,只要您用来对其进行排序的另一个 List L 是一致的 Comparable 即可。

      public class HeavyPair<L extends Comparable<L>, R> implements Comparable<HeavyPair<L, ?>> {
          public final L left;
          public final R right;
      
          public HeavyPair(L left, R right) {
              this.left = left;
              this.right = right;
          }
      
          public compareTo(HeavyPair<L, ?> o) {
              return this.left.compareTo(o.left);
          }
      
          public static <L extends Comparable<L>, R> List<R> sort(List<L> weights, List<R> toSort) {
              assert(weights.size() == toSort.size());
              List<R> output = new ArrayList<>(toSort.size());
              List<HeavyPair<L, R>> workHorse = new ArrayList<>(toSort.size());
              for(int i = 0; i < toSort.size(); i++) {
                  workHorse.add(new HeavyPair(weights.get(i), toSort.get(i)))
              }
              Collections.sort(workHorse);
              for(int i = 0; i < workHorse.size(); i++) {
                  output.add(workHorse.get(i).right);
              }
              return output;
          }
      }
      

      请原谅我在编写此代码时使用的任何糟糕做法。我很着急。

      只需拨打HeavyPair.sort(listB, listA);

      编辑:修正了这一行 return this.left.compareTo(o.left);。现在它确实有效了。

      【讨论】:

        【解决方案4】:

        使用 Java 8:

        Collections.sort(listToSort, 
            Comparator.comparing(item -> listWithOrder.indexOf(item)));
        

        或更好:

        listToSort.sort(Comparator.comparingInt(listWithOrder::indexOf));
        

        【讨论】:

        • 只是比第一个版本简单
        【解决方案5】:

        如果保证两个列表包含相同的元素,只是顺序不同,则可以使用List&lt;T&gt; listA = new ArrayList&lt;&gt;(listB),这将是O(n) 时间复杂度。否则,我在这里使用Collections.sort() 看到很多答案,但是有一种替代方法可以保证O(2n) 运行时,理论上它应该比sort 的最差时间复杂度O(nlog(n)) 更快,但代价是2n 存储空间

        Set<T> validItems = new HashSet<>(listB);
        listA.clear();
        listB.forEach(item -> {
          if(validItems.contains(item)) {
            listA.add(item);
          }
        });
        

        【讨论】:

          【解决方案6】:

          问题:根据另一个列表中存在的字段的所有可能值之一对 Pojo 列表进行排序。

          看看这个解决方案,可能这就是你想要实现的目标:

          import java.util.ArrayList;
          import java.util.Collections;
          import java.util.Comparator;
          import java.util.List;
          
          public class Test {
          
            public static void main(String[] args) {
              List<Employee> listToSort = new ArrayList<>();
              listToSort.add(new Employee("a", "age11"));
              listToSort.add(new Employee("c", "age33"));
              listToSort.add(new Employee("b", "age22"));
              listToSort.add(new Employee("a", "age111"));
              listToSort.add(new Employee("c", "age3"));
              listToSort.add(new Employee("b", "age2"));
              listToSort.add(new Employee("a", "age1"));
          
              List<String> listWithOrder = new ArrayList<>();
              listWithOrder.add("a");
              listWithOrder.add("b");
              listWithOrder.add("c");
          
              Collections.sort(listToSort, Comparator.comparing(item -> 
              listWithOrder.indexOf(item.getName())));
              System.out.println(listToSort);
            }
          
          }
          
          
          class Employee {
            String name;
            String age;
          
            public Employee(String name, String age) {
              super();
              this.name = name;
              this.age = age;
            }
          
            public String getName() {
              return name;
            }
          
            public String getAge() {
              return age;
            }
          
            @Override
            public String toString() {
              return "[name=" + name + ", age=" + age + "]";
            }
          }
          

          输出 [[姓名=a, 年龄=age11], [姓名=a, 年龄=age111], [姓名=a, 年龄=age1], [姓名=b, 年龄=age22], [姓名=b, 年龄=age2] , [name=c, age=age33], [name=c, age=age3]]

          【讨论】:

          • 如果 item.getName() 返回 null ,它将在排序后首先出现。如何让它最后。?
          【解决方案7】:
          import java.util.Comparator;
          import java.util.List;
          
          public class ListComparator implements Comparator<String> {
          
              private final List<String> orderedList;
              private boolean appendFirst;
          
              public ListComparator(List<String> orderedList, boolean appendFirst) {
                  this.orderedList = orderedList;
                  this.appendFirst = appendFirst;
              }
          
              @Override
              public int compare(String o1, String o2) {
                  if (orderedList.contains(o1) && orderedList.contains(o2))
                      return orderedList.indexOf(o1) - orderedList.indexOf(o2);
                  else if (orderedList.contains(o1))
                      return (appendFirst) ? 1 : -1;
                  else if (orderedList.contains(o2))
                      return (appendFirst) ? -1 : 1;
                  return 0;
              }
          }
          

          您可以使用此通用比较器根据另一个列表对列表进行排序。 例如,当 appendFirst 为 false 时,以下将是输出。

          有序列表:[a, b]

          无序列表:[d, a, b, c, e]

          输出: [a, b, d, c, e]

          【讨论】:

          • 这是对列表进行排序的一种非常好的方法,并且澄清一下,使用 appendFirst=true 调用会将列表排序为 [d, c, e, a, b]
          【解决方案8】:

          为避免非常低效的查找,您应该索引listB 中的项目,然后根据它对listA 进行排序。

          Map<Item, Integer> index = IntStream.range(0, listB.size()).boxed()
            .collect(Collectors.toMap(listB::get, x -> x));
          
          listA.sort((e1, e2) -> Integer.compare(index.get(c1), index.get(c2));
          

          【讨论】:

            【解决方案9】:

            刚刚遇到同样的问题。
            我有一个有序键的列表,我需要根据键的顺序对列表中的对象进行排序。
            我的列表足够长,使得时间复杂度为 N^2 的解决方案无法使用。
            我的解决方案:

            <K, T> List<T> sortByOrder(List<K> orderedKeys, List<T> objectsToOrder, Function<T, K> keyExtractor) {
                AtomicInteger ind = new AtomicInteger(0);
                Map<K, Integer> keyToIndex = orderedKeys.stream().collect(Collectors.toMap(k -> k, k -> ind.getAndIncrement(), (oldK, newK) -> oldK));
                SortedMap<Integer, T> indexToObj = new TreeMap<>();
                objectsToOrder.forEach(obj -> indexToObj.put(keyToIndex.get(keyExtractor.apply(obj)), obj));
                return new ArrayList<>(indexToObj.values());
            }
            

            时间复杂度为 O(N * Log(N))。
            该解决方案假定要排序的列表中的所有对象都具有不同的键。如果不是,那么只需将SortedMap&lt;Integer, T&gt; indexToObj 替换为SortedMap&lt;Integer, List&lt;T&gt;&gt; indexToObjList

            【讨论】:

              【解决方案10】:

              在 java 8 上试试这个:

              listB.sort((left, right) -> Integer.compare(list.indexOf(left), list.indexOf(right)));
              

              listB.sort(Comparator.comparingInt(item -> list.indexOf(item)));
              

              【讨论】:

                【解决方案11】:

                JB Nizet 答案的速度改进(来自他自己提出的建议)。用这个方法:

                • 对包含 1000 个项目的列表进行 100 次排序可提高我的速度 10 倍 单元测试。

                • 对包含 10000 个项目的列表进行 100 次排序可将我的速度提高 140 倍(整个批次为 265 毫秒而不是 37 秒) 单元测试。

                当两个列表不相同时,此方法也可以使用:

                /**
                 * Sorts list objectsToOrder based on the order of orderedObjects.
                 * 
                 * Make sure these objects have good equals() and hashCode() methods or
                 * that they reference the same objects.
                 */
                public static void sortList(List<?> objectsToOrder, List<?> orderedObjects) {
                
                    HashMap<Object, Integer> indexMap = new HashMap<>();
                    int index = 0;
                    for (Object object : orderedObjects) {
                        indexMap.put(object, index);
                        index++;
                    }
                
                    Collections.sort(objectsToOrder, new Comparator<Object>() {
                
                        public int compare(Object left, Object right) {
                
                            Integer leftIndex = indexMap.get(left);
                            Integer rightIndex = indexMap.get(right);
                            if (leftIndex == null) {
                                return -1;
                            }
                            if (rightIndex == null) {
                                return 1;
                            }
                
                            return Integer.compare(leftIndex, rightIndex);
                        }
                    });
                }
                

                【讨论】:

                • 最佳答案!也很容易扩展类似的问题!
                【解决方案12】:
                Collections.sort(listB, new Comparator<Item>() {
                    public int compare(Item left, Item right) {
                        return Integer.compare(listA.indexOf(left), listA.indexOf(right));
                    }
                });
                

                不过,这非常低效,您可能应该从 listA 创建一个 Map&lt;Item, Integer&gt; 以更快地查找项目的位置。

                Guava 有一个现成的比较器可以做到这一点:Ordering.explicit()

                【讨论】:

                • O(n) 查找大约发生 O(nlogn) 次?那是 O(n^2 logn)!你没开玩笑。
                • 请注意,Integer.compare 仅适用于 java 7。在 java 6 或更低版本中,您需要使用 Integer.valueOf(listA.indexOf(left)).compareTo(Integer.valueOf(listA.indexOf(right)))
                • 第二个Item 参数旁边多了一个,
                • 关于Ordering,下面是它的外观示例:Collections.sort(listA, Ordering.explicit(listB))。如果您现有的订单仅包含待排序对象的字段(例如 ID),请使用onResultOfOrdering.explicit(ids).onResultOf(item -&gt; item.getId())
                【解决方案13】:

                这里是一个示例,说明如何对列表进行排序,然后根据对第一个数组列表所做的更改在另一个列表中进行更改。这个技巧永远不会失败,并确保列表中的项目之间的映射。两个列表的大小必须相同才能使用此技巧。

                    ArrayList<String> listA = new ArrayList<String>();
                    ArrayList<String> listB = new ArrayList<String>();
                    int j = 0;
                    // list of returns of the compare method which will be used to manipulate
                    // the another comparator according to the sorting of previous listA
                    ArrayList<Integer> sortingMethodReturns = new ArrayList<Integer>();
                
                    public void addItemstoLists() {
                        listA.add("Value of Z");
                        listA.add("Value of C");
                        listA.add("Value of F");
                        listA.add("Value of A");
                        listA.add("Value of Y");
                
                        listB.add("this is the value of Z");
                        listB.add("this is the value off C");
                        listB.add("this is the value off F");
                        listB.add("this is the value off A");
                        listB.add("this is the value off Y");
                
                        Collections.sort(listA, new Comparator<String>() {
                
                            @Override
                            public int compare(String lhs, String rhs) {
                                // TODO Auto-generated method stub
                                int returning = lhs.compareTo(rhs);
                                sortingMethodReturns.add(returning);
                                return returning;
                            }
                
                        });
                        // now sort the list B according to the changes made with the order of
                        // items in listA
                        Collections.sort(listB, new Comparator<String>() {
                
                            @Override
                            public int compare(String lhs, String rhs) {
                                // TODO Auto-generated method stub
                
                                // comparator method will sort the second list also according to
                                // the changes made with list a
                                int returning = sortingMethodReturns.get(j);
                                j++;
                                return returning;
                            }
                
                        });
                
                    }
                

                【讨论】:

                  【解决方案14】:

                  试试这个。下面的代码适用于 listA 是 Objects 列表的场景,因为您没有指明特定类型。

                  Object[] orderedArray = new Object[listA.size()];
                  
                  for(int index = 0; index < listB.size(); index ++){
                      int position = listB.get(index); //this may have to be cast as an int
                      orderedArray[position] = listA.get(index);
                  }
                  //if you receive UnsupportedOperationException when running listA.clear()
                  //you should replace the line with listA = new List<Object>() 
                  //using your actual implementation of the List interface
                  listA.clear(); 
                  listA.addAll(orderedArray);
                  

                  【讨论】:

                    【解决方案15】:

                    IMO,你需要坚持别的东西。可能不是完整的列表 B,而是 something。可能只是用户更改的项目的索引。

                    【讨论】:

                      【解决方案16】:

                      在 Java 中,有一组类可用于对列表或数组进行排序。以下大多数示例都将使用列表,但同样的概念也适用于数组。一个示例将显示这一点。

                      我们可以通过创建一个整数列表来使用它,并使用 Collections.sort() 对它们进行排序。 Collections (Java Doc) 类(Java Collection Framework 的一部分)提供了一个静态方法列表,我们可以在处理诸如 list、set 等集合时使用这些方法。所以简而言之,我们可以通过简单地调用 java.util.Collections.sort(the list) 来对列表进行排序,如下例所示:

                      import java.util.ArrayList;
                      import java.util.Collections;
                      import java.util.List;
                      
                      public class example {
                        public static void main(String[] args) {
                          List<Integer> ints = new ArrayList<Integer>();
                          ints.add(4);
                          ints.add(3);
                          ints.add(7);
                          ints.add(5);
                          Collections.sort(ints);
                          System.out.println(ints);
                        }
                      }
                      

                      上面的类创建了一个包含四个整数的列表,并使用集合排序方法对这个列表进行排序(在一行代码中),我们不必担心排序算法。

                      【讨论】:

                        【解决方案17】:

                        根据您的设置,另一个可能有效的解决方案不是将实例存储在 listB 中,而是将索引存储在 listA 中。这可以通过将 listA 包装在自定义排序列表中来完成,如下所示:

                        public static class SortedDependingList<E> extends AbstractList<E> implements List<E>{
                            private final List<E> dependingList;
                            private final List<Integer> indices;
                        
                            public SortedDependingList(List<E> dependingList) {
                                super();
                                this.dependingList = dependingList;
                                indices = new ArrayList<>();
                            }
                        
                            @Override
                            public boolean add(E e) {
                                int index = dependingList.indexOf(e);
                                if (index != -1) {
                                    return addSorted(index);
                                }
                                return false;
                            }
                        
                            /**
                             * Adds to this list the element of the depending list at the given
                             * original index.
                             * @param index The index of the element to add.
                             * 
                             */
                            public boolean addByIndex(int index){
                                if (index < 0 || index >= this.dependingList.size()) {
                                    throw new IllegalArgumentException();
                                }
                                return addSorted(index);
                            }
                        
                            /**
                             * Returns true if this list contains the element at the
                             * index of the depending list.
                             */
                            public boolean containsIndex(int index){
                                int i = Collections.binarySearch(indices, index);
                                return i >= 0;
                            }
                        
                            private boolean addSorted(int index){
                                int insertIndex = Collections.binarySearch(indices, index);
                                if (insertIndex < 0){
                                    insertIndex = -insertIndex-1;
                                    this.indices.add(insertIndex, index);
                                    return true;
                                }
                                return false;
                            }
                        
                            @Override
                            public E get(int index) {
                                return dependingList.get(indices.get(index));
                            }
                        
                            @Override
                            public int size() {
                                return indices.size();
                            }
                        }
                        

                        那么你可以按如下方式使用这个自定义列表:

                        public static void main(String[] args) {
                            class SomeClass{
                                int index;
                                public SomeClass(int index) {
                                    super();
                                    this.index = index;
                                }
                                @Override
                                public String toString() {
                                    return ""+index;
                                }
                            }
                        
                            List<SomeClass> listA = new ArrayList<>();
                            for (int i = 0; i < 100; i++) {
                                listA.add(new SomeClass(i));
                            }
                            SortedDependingList<SomeClass> listB = new SortedDependingList<>(listA);
                            Random rand = new Random();
                        
                            // add elements by index:
                            for (int i = 0; i < 5; i++) {
                                int index = rand.nextInt(listA.size());
                                listB.addByIndex(index);
                            }
                        
                            System.out.println(listB);
                        
                            // add elements by identity:
                            for (int i = 0; i < 5; i++) {
                                int index = rand.nextInt(listA.size());
                                SomeClass o = listA.get(index);
                                listB.add(o);
                            }
                            System.out.println(listB);      
                        }
                        

                        当然,这个自定义列表只有在原始列表中的元素没有改变的情况下才有效。如果可以更改,您需要以某种方式监听原始列表的更改并更新自定义列表中的索引。

                        另请注意,SortedDependingList 目前不允许第二次添加 listA 中的元素 - 在这方面,它实际上就像 listA 中的一组元素一样,因为这通常是您在这样的设置中想要的。

                        向 SortedDependingList 添加内容的首选方法是已经知道元素的索引并通过调用 sortedList.addByIndex(index); 来添加它

                        【讨论】:

                          【解决方案18】:

                          假设您有一个listB 列表,该列表定义了您要对listA 进行排序的顺序。这只是一个示例,但它演示了由列表定义的顺序,而不是数据类型的自然顺序:

                          List<String> listB = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday",
                              "Thursday", "Friday", "Saturday");
                          

                          现在,假设listA 需要按照这个顺序进行排序。这是一个List&lt;Item&gt;,而Item 有一个public String getWeekday() 方法。

                          创建一个Map&lt;String, Integer&gt;,将listB 中所有内容的值映射到可以轻松排序的内容,例如索引,即"Sunday" => 0, ..., "Saturday" => 6。这将提供快速简便的查找。

                          Map<String, Integer> weekdayOrder = new HashMap<String, Integer>();
                          for (int i = 0; i < listB.size(); i++)
                          {
                              String weekday = listB.get(i);
                              weekdayOrder.put(weekday, i);
                          }
                          

                          然后您可以创建自定义Comparator&lt;Item&gt;,使用Map 创建订单:

                          public class ItemWeekdayComparator implements Comparator<Item>
                          {
                              private Map<String, Integer> sortOrder;
                          
                              public ItemWeekdayComparator(Map<String, Integer> sortOrder)
                              {
                                  this.sortOrder = sortOrder;
                              }
                          
                              @Override
                              public int compare(Item i1, Item i2)
                              {
                                  Integer weekdayPos1 = sortOrder.get(i1.getWeekday());
                                  if (weekdayPos1 == null)
                                  {
                                      throw new IllegalArgumentException("Bad weekday encountered: " +
                                         i1.getWeekday());
                                  }
                                  Integer weekdayPos2 = sortOrder.get(i2.getWeekday());
                                  if (weekdayPos2 == null)
                                  {
                                      throw new IllegalArgumentException("Bad weekday encountered: " +
                                         i2.getWeekday());
                                  }
                                  return weekdayPos1.compareTo(weekdayPos2);
                              }
                          }
                          

                          然后您可以使用自定义的ComparatorlistA 进行排序。

                          Collections.sort(listA, new ItemWeekdayComparator(weekdayOrder));
                          

                          【讨论】:

                            【解决方案19】:

                            不完全清楚你想要什么,但如果是这种情况: A:[c,b,a] B:[2,1,0]

                            您想同时加载它们,然后生成: C:[a,b,c]

                            那么也许是这个?

                            List c = new ArrayList(b.size());
                            for(int i=0;i<b.size();i++) {
                              c.set(b.get(i),a.get(i));
                            }
                            

                            这需要一个额外的副本,但我认为它的效率要低得多,而且各种不清楚:

                            for(int i=0;i<b.size();i++){
                                int from = b.get(i);
                                if(from == i) continue;
                                T tmp = a.get(i);
                                a.set(i,a.get(from));
                                a.set(from,tmp);
                                b.set(b.lastIndexOf(i),from); 
                            }
                            

                            请注意,我也没有测试,可能有一个标志被翻转了。

                            【讨论】:

                              【解决方案20】:

                              就像 Tim Herold 写的,如果对象引用应该相同,您可以将 listB 复制到 listA,或者:

                              listA = new ArrayList(listB);
                              

                              如果您不想更改 listA 所指的列表,则可以这样做:

                              listA.clear();
                              listA.addAll(listB);
                              

                              如果引用不相同但listA 和listB 中的对象之间存在某种等价关系,您可以使用自定义Comparator 对listA 进行排序,该Comparator 在listB 中查找对象并使用其在listB 中的索引作为排序键。暴力搜索 listB 的幼稚实现在性能方面不是最好的,但在功能上就足够了。

                              【讨论】:

                              • 请参阅 JB Nizet 的回答,了解执行此操作的自定义比较器的示例。
                              【解决方案21】:

                              这样做的一种方法是遍历 listB 并在 listA 包含项目时将项目添加到临时列表中:

                              List<?> tempList = new ArrayList<?>();
                              for(Object o : listB) {
                                  if(listA.contains(o)) {
                                      tempList.add(o);
                                  }
                              }
                              listA.removeAll(listB);
                              tempList.addAll(listA);
                              return tempList;
                              

                              【讨论】:

                              • @boxed__l:它将两个列表中包含的元素以相同的顺序排序,并将仅包含在A中的元素添加到末尾。例如,如果listA{0, 1, 6, 4, 5}listB{0, 1, 2, 3, 4},方法会返回{0, 2, 4, 6, 5}
                              • 这个答案有一个主要问题:您正在将对 listB 中的对象的引用插入到 listA 中,如果两个对象是 equals() 但不引用相同,则这是不正确的行为object - listA 中的原始对象丢失,listA 中的一些引用被 listB 中的引用替换,而不是简单地重新排序 listA。
                              • 第二个问题是,如果 listA 和 listB 确实包含对相同对象的引用(当然,这使得第一个问题没有实际意义),并且它们包含相同的对象(正如他所说的 OP 所暗示的那样“重新排序”),那么整个事情就和listA.clear(); listA.addAll(listB);一样。
                              • 第三个主要问题是,在这个函数结束时,你会留下一些非常奇怪的副作用。您返回 tempList,其中包含来自 listB 和 listA 的对象的可能组合,并且 listA 已经删除了一些对象。如果您首先构建 tempList ,则意味着您希望在没有副作用的情况下完成所有这些操作,但 listA 留下了许多(如果不是全部)对象。
                              • 基本上,这个答案是无稽之谈。我知道你的目标是什么,但你需要重新考虑你的目标并编辑这个答案。
                              【解决方案22】:

                              如果对象引用应该相同,可以初始化listA new。

                              listA = new ArrayList(listB)
                              

                              【讨论】:

                              • 虽然我不完全确定 OP 到底要求什么,但我还是忍不住得出了这个结论。
                              • 第二组可能是第一组的子集。在这种情况下,这个答案有点有效,但只需要是集合的交集(删除缺失的元素)
                              猜你喜欢
                              • 1970-01-01
                              • 2018-11-15
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多