2011-10-23 27 views
5

Đối tượng List có phương thức mkString có thể chuyển đổi thành chuỗi có seperator. Tuy nhiên, hầu hết ngôn ngữ của con người đối xử với yếu tố cuối cùng khác nhau khi liệt kê một danh sách. Ví dụ A, B, C và D.Cách tốt nhất để liệt kê một danh sách bằng ngôn ngữ tự nhiên (Scala) là gì?

Điều gì là tốt nhất về kích thước mã và hiệu quả hợp lý để thực hiện việc này? Để được chính xác, tôi đang tìm kiếm một chức năng mà đáp ứng:

assertEquals("",foo(List())) 
assertEquals("A",foo(List("A"))) 
assertEquals("A and B",foo("List("A","B"))) 
assertEquals("A, B and C", foo(List("A","B","C"))) 
assertEquals("A, B, C and D", foo(List("A","B","C","D"))) 
+2

Nhưng còn về Oxford Comma thì sao? http://en.wikipedia.org/wiki/Serial_comma –

Trả lời

9
def foo(xs: List[String]) = 
    (xs.dropRight(2) :\ xs.takeRight(2).mkString(" and "))(_+", "+_) 

chỉnh sửa: Di chuyển này ht có một chút rõ ràng hơn:

def foo(xs: List[String]) = 
    (xs.dropRight(2) :+ xs.takeRight(2).mkString(" and ")).mkString(", ") 

@axaluss Tốc độ phụ thuộc vào độ dài danh sách. Với độ dài danh sách trung bình trên khoảng 4 phần tử, phiên bản thứ hai này nhanh hơn so với phiên bản của Tomasz. Nếu không, nó hơi chậm hơn.

+0

là phiên bản nhanh nhất của bạn? ít nhất là ngắn nhất;) – axaluss

4
def foo(list: List[String]) = list match{ 
    case Nil => "" 
    case _ if list.length == 1 => list.first 
    case _ => list.init.mkString(", ") + " and " + list.last 
} 
+0

Đây là phiên bản của riêng tôi: 'def naturalMakeString (danh sách: List [Any], sep1: String, sep2: String) = nếu danh sách (list.length <2). mkString else list.init.mkString (sep1) + sep2 + list.last' tuy nhiên cả bạn và của tôi không ngắn và không hiệu quả (sử dụng init và last) – baldur

+2

Sử dụng 'x :: Nil => x' làm trường hợp thứ hai, và 'case x => x.init ...' là thứ ba ngắn hơn một chút –

8

mất của tôi:

def foo[T](list: List[T]): String = list match { 
    case Nil => "" 
    case x :: Nil => x.toString 
    case x :: y :: Nil => x + " and " + y 
    case x :: rs => x + ", " + foo(rs) 
} 

Ngoài ra để sử dụng đệ quy đuôi:

@tailrec def str[T](cur: String, list: List[T]): String = list match { 
    case Nil => cur 
    case x :: Nil => cur + x 
    case x :: y :: Nil => cur + x + " and " + y 
    case x :: rs => str(cur + x + ", ", rs) 
} 

def foo[T](list: List[T]) = str("", list) 
Các vấn đề liên quan