Scala'da bir liste iki alana göre nasıl sıralanır?


101

Scala'da bir listeyi iki alana göre nasıl sıralayabilirim, bu örnekte lastName ve firstName'e göre sıralayacağım?

case class Row(var firstName: String, var lastName: String, var city: String)

var rows = List(new Row("Oscar", "Wilde", "London"),
                new Row("Otto",  "Swift", "Berlin"),
                new Row("Carl",  "Swift", "Paris"),
                new Row("Hans",  "Swift", "Dublin"),
                new Row("Hugo",  "Swift", "Sligo"))

rows.sortBy(_.lastName)

Bunun gibi şeyleri deniyorum

rows.sortBy(_.lastName + _.firstName)

ama işe yaramıyor. Bu yüzden iyi ve kolay bir çözümü merak ediyorum.

Yanıtlar:


217
rows.sortBy(r => (r.lastName, r.firstName))

4
ya lastName'de sıralamayı tersine çevirmek ve sonra firstName'de doğal sıralamayı yapmak istersek?
Sachin K

15
@SachinK: Kendi oluşturmak zorunda Orderingiçin Rowsınıf ve ile kullanmak sortedböyle yöntemle: rows.sorted(customOrdering). Ayrıca, özel kullanabilirsiniz Orderingiçin Tuple2böyle: rows.sortBy(r => (r.lastName, r.firstName))( Ordering.Tuple2(Ordering.String.reverse, Ordering.String) ).
senia

5
@SachinK: Sen uygulamak olabilir customOrderingolarak Ordering[Row]elle veya kullanma Ordering.by: Böyle val customOrdering = Ordering.by ((r: Satır) => (r.lastName, r.firstName)) (Ordering.Tuple2 (Ordering.String.reverse, Ordering.String)) `
senia

1
Mükemmel. Veya azalan düzende sıralamak içinrows.sortBy(r => (-r.field1, -r.field2))
Brent Faust

@BrentFaust -ile kullanamazsınız String. Sen kullanmalıdır Ordering::reversebu şekilde: rows.sortBy(r => (r.lastName, r.firstName))(implicitly[Ordering[(String, String)]].reverse).
senia

12
rows.sortBy (row => row.lastName + row.firstName)

Sorunuzda olduğu gibi birleştirilmiş adlara göre sıralamak isterseniz veya

rows.sortBy (row => (row.lastName, row.firstName))

önce soyadına göre sıralamak istiyorsanız, ardından ad; daha uzun isimler için uygun (Wild, Wilder, Wilderman).

Eğer yazarsan

rows.sortBy(_.lastName + _.firstName)

iki alt çizgi ile yöntem iki parametre bekler:

<console>:14: error: wrong number of parameters; expected = 1
       rows.sortBy (_.lastName + _.firstName)
                               ^

1
Bunun sıralaması, büyük olasılıkla ad ve soyadına göre sıralama ile aynı olmayacaktır.
Marcin

1
Özellikle, soyadları diffferent uzunlukları olduğunda
Luigi Plinge

7

Genel olarak, kararlı bir sıralama algoritması kullanırsanız, sadece bir tuşa göre sıralayabilirsiniz, sonra diğerine.

rows.sortBy(_.firstName).sortBy(_.lastName)

Nihai sonuç soyadına göre, sonra eşit olduğu yerde ada göre sıralanacaktır.


Scala'nın sortBykararlı sıralama kullandığından emin misiniz ? Aksi takdirde bu cevap anlamsızdır.
om-nom-nom

1
@ om-nom-nom: scala-lang.org/api/current/scala/util/Sorting$.html quickSort yalnızca değer türleri için tanımlanmıştır, bu nedenle evet.
Marcin

1
rowsdeğişmez bir listedir ve sortByüzerinde çalıştığı şeyi değiştirmek yerine (değişebilir sınıflarda bile) yeni bir değer döndürür. Yani ikinci ifadeniz sadece orijinal sıralanmamış listeyi sıralıyor.
Luigi Plinge

3
Scala, sortBy yönteminin altında, nesneler dizisi için kararlı olmayı garanti eden java.util.Arrays.sort kullanır. Yani evet, bu çözüm doğru. (Bu Scala 2.10'da kontrol edildi)
Marcin Pieciukiewicz

1
Bir demet oluşturan tek bir sortBy'ye karşı bunun performansını düşünmek ilginç. Bu yaklaşımla açıkça bu tupleları yaratmak zorunda değilsiniz, ancak tuple yaklaşımı ile sadece soyadların eşleştiği ilk isimleri karşılaştırmanız gerekir. Ama sanırım önemli değil - performans açısından kritik kod yazıyorsanız sortBy'yi hiç kullanmamalısınız!
AmigoNico

-3

Belki bu yalnızca Kayıt Listesi için işe yarar, ancak

scala> var zz = List((1, 0.1), (2, 0.5), (3, 0.6), (4, 0.3), (5, 0.1))
zz: List[(Int, Double)] = List((1,0.1), (2,0.5), (3,0.6), (4,0.3), (5,0.1))

scala> zz.sortBy( x => (-x._2, x._1))
res54: List[(Int, Double)] = List((3,0.6), (2,0.5), (4,0.3), (1,0.1), (5,0.1))

işe yarıyor ve bunu ifade etmenin basit bir yolu gibi görünüyor.


Ancak, OP'nin sıraladığı şey dizeler için çalışmaz.
Arketipsel Paul

Bu sorunun halihazırda çok sayıda iyi alınmış cevabı var ve bu cevaplar listelerle sınırlı değil. Öyleyse onu göndermenin sebebi nedir?
honk

@honk: Önceki çözümler aslında Tuple Listesinde çalışmıyor (AFAICT). Bir Scala acemi olmasaydım, bu durumda işe yarayacak önceki çözümleri nasıl değiştireceğimi belki anlayabilirdim, ama bugün yapmıyorum. Cevabımın, başka bir Scala acemisinin yapmaya çalıştığım şeyi yapmasına yardımcı olabileceğini düşündüm.
spreinhardt

@ user3508605: Katkıda bulunma isteğinizi takdir ediyorum. Bununla birlikte, Stack Overflow fikri, belirli problemleri olan sorulara sahip olmaktır (burada olduğu gibi) ve bu spesifik problemleri (ve sadece bunları) ele alan cevapları vardır. Cevabınız farklı bir problem için çözüm sunuyor. Bu nedenle, bunu göndermek için yanlış yer burası. Cevabınızın değerli olduğunu düşünüyorsanız, yeni bir soru sorun. Karşılık gelen sorunu yeni soruda açıklayın ve ardından cevabınızı oraya gönderin. Son olarak cevabınızı buradan kaldırmayı unutmayın. İşbirliğiniz için teşekkürler!
honk

@honk: Elbette, cevabımı ayrı bir soruya taşıyacağım. Ve, bu sorunun önceki cevabına (Marcin'den) bir yorum eklemenizi size dayatabilirsem, bu tamamen yanlış gibi görünüyor. (Üzerine gönderi yapabilmek için yeterli güvenilirlik puanım yok.) Bu yanıttaki örnek, önce bir anahtarla sıralar ve ardından farklı bir anahtara göre yeniden sıralar ve birinci sıradaki sonuçları etkili bir şekilde ortadan kaldırır. En azından Tuples Listesinde var.
spreinhardt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.