2016-01-15 29 views
5

Tôi có một tập tin chứa dữ liệu trên Salesman, sản phẩm, địa điểm, SalesValueTạo và tích lũy một bản đồ của Bản đồ Bản đồ ... trong scala

Ví dụ:

Bob, Carrots, United States, 200 
Bill, Potatoes, England, 100 
Bob, Oranges, England, 50 
Bob, Carrots, United States, 20 

Các SalesValue có thể ngắn gọn được tích lũy vào băm băm của hàm băm trong perl bằng cách sử dụng mã sau đây

while(<>){ 
    @cols = split(/,/); 
    $vals {$cols[0]} {$cols[1]} {$cols[2]} += $cols[3]; 
} 

Có ai có đề xuất cách tạo bản đồ bản đồ, cộng với sự tích lũy, tốt nhất có thể là tôi thực hiện trong scala?

Trả lời

6

Tôi khuyên bạn nên xem việc hợp nhất các bản đồ này là hoạt động monoid-append.

Đầu tiên chúng ta tạo ra các bản đồ bản đồ bản đồ như các yếu tố duy nhất:

val input = """Bob, Carrots, United States, 200 
       |Bill, Potatoes, England, 100 
       |Bob, Oranges, England, 50 
       |Bob, Carrots, United States, 20""".stripMargin.lines.toList 

val mmm = input.map(_.split(", ")) 
       .map { case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) } 

mmm là loại List[Map[String, Map[String, Map[String, Int]]]]:

List[Map[String, 
        Map[String, 
           Map[String, Int]]]] 

Sau đó, chúng ta có thể suml sử dụng một thư viện như scalaz hoặc cats:

import scalaz._, Scalaz._ 

println(mmm.suml) 

này sẽ in (không idented):

Map(Bill -> Map(Potatoes -> Map(England -> 100)), 
    Bob -> Map(Oranges -> Map(England -> 50), 
       Carrots -> Map(United States -> 220))) 

Để giúp hiểu những gì đang xảy ra đằng sau những hoạt động .suml tôi sẽ trơ trẽn đề nghị để kiểm tra trình bày này tôi đã thực hiện năm ngoái https://speakerdeck.com/filippovitale/will-it-blend-scalasyd-february-2015


EDIT

Chúng tôi cũng có thể xem bản đồ bản đồ của chúng tôi dưới dạng Foldable và sử dụng foldMap cho kết quả tương tự:

input.map(_.split(", ")) 
    .foldMap{ case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) } 
+2

Nói cách khác, Perl là người chiến thắng ở đây;) – Ashalynd

+0

... vâng, nhưng tôi đợi Perl6 trước khi sử dụng nó một lần nữa :-P Sau này troll tôi sẽ cập nhật câu trả lời với một số giải thích chi tiết hơn và một câu trả lời thay thế –

+0

cách tuyệt vời để đọc vào một bản đồ của bản đồ oof Maps ... – BarneyW

0

Filippo Vitale là ngắn gọn hơn và thanh lịch

Đây là một giải pháp bruteforce:

val t = 
    """Bob, Carrots, United States, 200 
    |Bill, Potatoes, England, 100 
    |Bob, Oranges, England, 50 
    |Bob, Carrots, United States, 20""".stripMargin 

def commaSplit(s: String) = s.splitAt(s.indexOf(",")) 

def f(arg: Seq[String]) = 
    arg 
    .groupBy(commaSplit(_)._1) 
    .map{ case (key, values) => key -> values.map(commaSplit(_)._2.drop(2))} 

val res = 
    f(t.split("\n")) 
    .map{ case (key, values) => key -> f(values).map { case (k, v) => 
     k -> f(v).map { case (country, amount) => country -> amount.map(_.toInt).sum } 
    }} 

cung cấp cho kết quả này:

Map(Bob -> Map(Carrots -> Map(United States -> 220), 
       Oranges -> Map(England -> 50)), 
    Bill -> Map(Potatoes -> Map(England -> 100))) 
Các vấn đề liên quan