【问题标题】:Sorting list or getAll in GrailsGrails 中的排序列表或 getAll
【发布时间】:2012-06-26 02:17:19
【问题描述】:

我想在我的域类中实现默认排序顺序,但立即发现它不适用于 getAll 方法。没什么大不了的,我只是用list 代替。问题是域类中的默认排序顺序不允许您指定多个排序字段 (as seen here)。

我的目标是首先按照 Bar 对象的名称对所有 Foo 对象进行排序,然后按照它们自己的名称排序。

class Foo {
    String name
    String Bar
}

class Bar {
    String name
}

如何在域类中实现这一点,这样我就不必在每次调用 .list() 时都指定一个冗长/讨厌的比较器?

我的一个尝试:

static Comparator getComparator() { 
    def c = { a, b -> 
    def result = a.bar.name.compareTo( b.bar.name ); 
        if ( result == 0 ) {
            result = a.name.compareTo( b.name );
        }
    }
    return c as Comparator
}

然后我可以打电话给Foo.list(Foo.getComparator())...如果我能让它工作的话。

更新:

我想我在这里真的很接近,只是在同一个排序闭包中实现两个比较时遇到了麻烦。

Foo.list().sort{ a, b ->
    def result = a.bar.name <=> b.bar.name;
    // Things mess up when I put this if statement in.
    if( result == 0 ) {
        a.name <=> b.name
    }
}

迪斯科!

class Foo { // My domain class
    // ...

    static Comparator getComparator() {
        def c =[
            compare: { a, b ->
                def result = a.bar.name <=> b.bar.name;
                if( result == 0 ) {
                    result = a.name <=> b.name
                }
                return result
            }
        ] as Comparator
    }

    // ...
}

并在我的控制器中这样实现:

Foo.list().sort( Foo.getComparator() )

PS:

上述方法有效,但 Jeff Storey 在我发现后在他的答案中发布了一些代码,他的代码有效并且比我的要好得多,所以使用它:)

【问题讨论】:

  • 看起来你找到了答案,仅供参考,使用a.bar.name &lt;=&gt; b.bar.name ?: a.name &lt;=&gt; b.name 是带有后备比较键的惯用常规情况。另外,由于这些是域对象,如果可以的话,我建议您在数据库中进行排序。除非它们的集合非常小,否则在 groovy 中执行此操作可能会慢几个数量级。
  • 在数据库中做意味着通过executeQuery方法的HQL对吗?
  • 是的,我就是这样做的。您可能也可以为此使用条件,但我发现条件写起来比 HQL 更难写,HQL 非常接近 SQL。

标签: grails groovy


【解决方案1】:

在您的情况下,让 Foo 实现 Comparable 并且实现可以按照您的描述进行比较是否有意义?然后当你对列表中的对象进行排序时,因为它们是Comparable,它们会正确排序。

如果你实现Comparable 没有意义,你需要指定一个比较器来排序。

以下是一些基于您的 cmets 的示例代码:

编辑:

class Person implements Comparable<Person> {

   String firstName
   String lastName

   int compareTo(Person other) {
       int lastNameCompare = lastName <=> other.lastName
       return lastNameCompare != 0 ? lastNameCompare : firstName <=> other.firstName
   }

   String toString() {
     "${lastName},${firstName}"
   }
}

def people = [new Person(firstName:"John",lastName:"Smith"), new Person(firstName:"Bill",lastName:"Jones"), new Person(firstName:"Adam",lastName:"Smith")]
println "unsorted = ${people}"
println "sorted = ${people.sort()}" 

打印出来:

unsorted = [Smith,John, Jones,Bill, Smith,Adam]
sorted = [Jones,Bill, Smith,Adam, Smith,John]

【讨论】:

  • 如果我实现了 Comparable 接口,如何让 Grails 使用它进行排序?我知道如何比较两个对象foo1.compareTo(foo2),但我需要在对象列表上实现它。
  • 对,我不认为实现可比较的接口是我的问题(尽管我确实尝试过,正如您在我的问题的“我的尝试之一”中使用 compareTo 所看到的那样) .我已经可以与a.bar.name &lt;=&gt; b.bar.name 的闭包做一个不错的比较。我认为我的大多数问题都来自同时按两个字段排序。一个更容易理解的例子,想象先按姓氏排序,然后按名字排序。因此,如果有两个姓氏为Smith Adam Smith 的人将排在John Smith 之前。
  • 啊,如果你的代码是正确的,那这就是我要找的。我没有意识到在实现compareTo() 方法之后简单地调用.sort() 实际上会使用compareTo() 方法。我会试一试,因为它比我的解决方案要干净得多。谢谢!
【解决方案2】:

为了进一步简化上面的帖子(我会对此发表评论,但我还没有代表),您可以使用 elvis 运算符链接 groovy 比较运算符:

class Person implements Comparable<Person> {

    String firstName
    String lastName

    int compareTo(Person other) {
        return lastName <=> other.lastName ?: firstName <=> other.firstName
    }

    String toString() {
        "${lastName},${firstName}"
    }
}

def people = [new Person(firstName:"John",lastName:"Smith"), new Person(firstName:"Bill",lastName:"Jones"), new     Person(firstName:"Adam",lastName:"Smith")]
println "unsorted = ${people}"
println "sorted = ${people.sort()}"

这将为您提供相同的结果,因为 0 在 groovy 眼中被认为是错误的,这将使它查看链中的下一个条件。

【讨论】:

    猜你喜欢
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 2015-06-21
    • 2021-01-18
    • 2016-01-26
    • 1970-01-01
    相关资源
    最近更新 更多