【问题标题】:Sort a array list of generic objects Java对泛型对象的数组列表进行排序Java
【发布时间】:2019-06-09 18:50:36
【问题描述】:

我有一个 Vertex 类,它有一个泛型类型 T 的字段元素。

我有一个 Vertex 对象的 ArrayList,我想对其进行排序,但我不确定如何排序。

我尝试使用如下所示的比较器:

listOfNeighbours.sort(new Comparator<Vertex<T>>() {
        @Override
        public int compare(Vertex<T> v1, Vertex<T> v2) {
            if(v1.getElement() == v2.getElement()){
                return 0;
            }else if(v1.getElement() < v2.getElement()) {
                return -1;
            }else {
                return 1;
            }

         }
    });

显然,上面的解决方案是错误的,因为我们无法比较泛型,但我想要类似的东西来对我的 Vertex 对象列表进行排序。

在我的应用程序中,T 可以是整数、双精度或字符串。

感谢任何帮助!

谢谢。

编辑:我的顶点类如下:

public class Vertex<T>{

private ObjectProperty<T> element;
private BooleanProperty visited;

public Vertex() {
    element = null;
    visited = new SimpleBooleanProperty(false);
}

public Vertex(T element) {
    this.element = new SimpleObjectProperty<T>(element);
    this.visited = new SimpleBooleanProperty(false);
}

public Vertex(T element, boolean visited) {
    this.element = new SimpleObjectProperty<T>(element);
    this.visited = new SimpleBooleanProperty(visited);
}

public void setElement(T elem) {
    this.element.set(elem);
}

public T getElement() {
    return this.element.get();
}

public ObjectProperty<T> elementProperty(){
    return this.element;
}

public void setVisited(boolean b) {
    this.visited.set(b);
}

public boolean isVisited() {
    return this.visited.get();
}

public BooleanProperty visitedProperty(){
    return this.visited;
}

@Override
public boolean equals(Object o) {
    if(o == this) {
        return true;
    }

    if(!(o instanceof Vertex<?>)) {
        return false;
    }

    Vertex<?> v=  (Vertex<?>) o;

    if(v.getElement() instanceof String) {
        return v.getElement().equals(this.element.get());
    }else {
        return v.getElement() == this.element.get();
    }


}

@Override
public String toString() {
    return element.get().toString();
}

}

【问题讨论】:

  • v1.getElement() == v2.getElement() 不是比较,它只是检查内存地址。你的代码应该只是return v1.getElement().compareTo(v2.getElement())。顶点元素必须实现Comparable

标签: java sorting generics arraylist


【解决方案1】:

Comparator 是个好东西。对于这个特定问题,它有一个static &lt;T,U extends Comparable&lt;? super U&gt;&gt; Comparator&lt;T&gt; comparing(Function&lt;? super T,? extends U&gt; keyExtractor)。在你的情况下,那将是

listOfNeighbours.sort(Comparator.comparing(Vertex::getElement))

如果您的 Vertex 组件不是 Comparable,我建议您使用 static &lt;T,U&gt; Comparator&lt;T&gt; comparing(Function&lt;? super T,? extends U&gt; keyExtractor, Comparator&lt;? super U&gt; keyComparator),而不是使用自定义比较器。

例如,

import java.util.*;
import javafx.beans.property.*;

public class Vertex<T>{

  private ObjectProperty<T> element;
  private BooleanProperty visited;

  public Vertex() {
      element = null;
      visited = new SimpleBooleanProperty(false);
  }

  public Vertex(T element) {
      this.element = new SimpleObjectProperty<T>(element);
      this.visited = new SimpleBooleanProperty(false);
  }

  public Vertex(T element, boolean visited) {
      this.element = new SimpleObjectProperty<T>(element);
      this.visited = new SimpleBooleanProperty(visited);
  }

  public void setElement(T elem) {
      this.element.set(elem);
  }

  public T getElement() {
      return this.element.get();
  }

  public ObjectProperty<T> elementProperty(){
      return this.element;
  }

  public void setVisited(boolean b) {
      this.visited.set(b);
  }

  public boolean isVisited() {
      return this.visited.get();
  }

  public BooleanProperty visitedProperty(){
      return this.visited;
  }

  @Override
  public boolean equals(Object o) {
      if(o == this) {
          return true;
      }

      if(!(o instanceof Vertex<?>)) {
          return false;
      }

      Vertex<?> v=  (Vertex<?>) o;

      if(v.getElement() instanceof String) {
          return v.getElement().equals(this.element.get());
      }else {
          return v.getElement() == this.element.get();
      }


  }

  @Override
  public String toString() {
      return element.get().toString();
  }

  public static void main(String[] args) {
    ArrayList<Vertex<String>> listOfNeighbours = new ArrayList<>();
    listOfNeighbours.add(new Vertex<>("foo"));
    listOfNeighbours.add(new Vertex<>("bar"));
    System.out.println(listOfNeighbours);
    listOfNeighbours.sort(Comparator.comparing(Vertex::getElement));
    System.out.println(listOfNeighbours);

    ArrayList<Vertex<Integer>> list2 = new ArrayList<>();
    list2.add(new Vertex<>(1));
    list2.add(new Vertex<>(123));
    list2.add(new Vertex<>(15));
    list2.add(new Vertex<>(2));
    System.out.println(list2);
    list2.sort(Comparator.comparing(Vertex::getElement));
    System.out.println(list2);
    list2.sort(Comparator.comparing(Vertex::getElement, Comparator.comparing(i -> i.toString())));
    System.out.println(list2);
  }
}

应该是怎么做的(用https://www.compilejava.net/测试)。

结果是

[foo, bar]

(原始输入)

[bar, foo]

(按字符串排序)

[1, 123, 15, 2]

(原始输入)

[1, 2, 15, 123]

(按整数自然顺序排序)

[1, 123, 15, 2]

(按给定的字符串顺序排序,即按字典顺序)。

后者使用Comparator&lt;Vertex&lt;Integer&gt;&gt; 完成,它通过从给定的Vertex&lt;Integer&gt; 中提取值然后将其转换为String 来完成其工作,然后将其用作排序键。

【讨论】:

  • 此解决方案假定TComparable&lt;? super T&gt;,但通常情况并非如此。
  • 也就是说我只是注意到在问题中 T 始终是 Integer、Double、String 之一,所有这些都是 Comparables 所以我想只要他确实对T 施加限制就足够了,据我所见,如果他不能控制他的 Graph/Vertex 类源代码,他可能没有或可能没有能力这样做,所以我仍然建议添加一个不这样做的解决方案一个假设。
  • @ValentinRuano 你是对的。在这种情况下(它们可以比较,但不是Comparable),我建议改为static &lt;T,U&gt; Comparator&lt;T&gt; comparing(Function&lt;? super T,? extends U&gt; keyExtractor, Comparator&lt;? super U&gt; keyComparator)
  • 大家好,我还是有点困惑@glglgl 我在上面尝试了您的解决方案,但出现错误。它说“Vertex 类型未定义适用于此处的 getElement(Object)”。
  • 不确定这是否相关,但在我的 Vertex 类中,元素字段的类型为 ObjectProperty,但我的 getElement() 方法返回的类型为 T。
【解决方案2】:

如果 T 被限制为 Comparable&lt;? super T&gt; @glglgl 上面的解决方案就足够了,因为似乎 T 根据问题可能采用的任何类型都符合要求。

但是,如果 T 不受这种限制,并且您不能或不想更改它,则解决方案会稍微更通用,并且需要调用代码为 T 元素显式提供比较器作为Comparator.comparing的第二个参数

static <T> void sortNeightbours(Collection<Vertex<? extends T>> neighbours, Comparator<? super T> elementComparator) {
    neighbours.sort(Comparator.comparing(Vertex::getElement, elementComparator);
} 

你不需要为此定义一个单独的(静态)方法,如果你愿意,它可以被内联。

对于元素类型与IntegerDoubleString 类似的顶点,调用代码将是相同的:

   List<Vertex<Integer>> ints = ...;
   List<Vertex<Double>> dbls = ...;
   List<Vertex<String>> strs = ...;

   sortNeighbours(ints, Comparator.naturalOrder());
   sortNeighbours(dbls, Comparator.naturalOrder());
   sortNeighbours(strs, Comparator.naturalOrder());

您可以定义一个额外的方法来处理 Comparables,这样您就不必每次都在代码中添加 naturalOrder() 调用。

【讨论】:

  • 嗨@Valentin Ruano 我收到一条错误消息,提示“未定义集合类型的方法 naturalOrder()。”
  • 啊抱歉它是在Comparator 而不是Collections 中定义的,我的错。我相应地更新了答案,谢谢。
【解决方案3】:

问题是您是否知道要进行比较时 Vertex 中的元素类型。

即由于类型擦除,此代码有效:

Vertex<String> strVtx = ...
Vertex<Integer> intVtx = ...
List<Vertex> list = Arrays.asList(strVtx, intVtx);
list.sort(aComparer);

所以这里的比较器实现需要不确定。

但是,如果您确实知道类型,您可以简单地做:

List<Vertex<Integer>> list = ...
list.sort(Comparator.comparing(Vertex::getElement);

【讨论】:

  • Vertex&lt;int&gt; 不是有效的 Java。此外,鉴于问题表明存在 Vertex.getElement 以获得要比较的值,您可以通过适当地使用该方法来改善您的答案。
猜你喜欢
  • 2016-03-01
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
  • 2019-04-17
  • 1970-01-01
  • 2018-03-08
  • 2012-10-14
  • 1970-01-01
相关资源
最近更新 更多