使用两个条件筛选列表并创建地图scala

时间:2017-08-21 08:14:25

标签: scala functional-programming mapreduce

我有一个保持交易的案例类(假设为资金转移)。为简单起见,我将在下面使用

case class Trans(from: String, to: String, amount: Int)

我有交易清单

val tl = List(
  Trans("a", "b", 30), 
  Trans("a", "c", 40),
  Trans("b", "c", 10),
  Trans("b", "a", 25),
  Trans("c", "a", 15)
)

我想根据对此列表进行分组。然后需要将组的总和加到 Map 。地图将元素保存在以下结构中

("a" -> (70, 40))
// "a" is the key
// "70" is the sum of values where "a" is 'from' (30 + 40)
// "40" is the sum of values where "a" is 'to' (25 + 15)

对于实例,about列表应将输出填充为

Map("a" -> (70, 40), "b" -> (35, 30), "c" -> (15, 50))

我可以使用两个语句进行过滤,并将它们组合起来,如下所示

// out map
val mOut = tl.map(t => (t.from, t.amount)).groupBy(_._1).map(s => (s._1, s._2.sum))

// in map
val mIn = tl.map(t => (t.to, t.amount)).groupBy(_._1).map(s => (s._1, s._2.sum))

// finally I can join these tow maps to have the final output

有没有办法用单/一个声明来做?

3 个答案:

答案 0 :(得分:2)

如果您是catsscalaz用户,则可以使用foldMap

import cats._, implicits._ // or...
//import scalaz._, Scalaz._


case class Trans(from: String, to: String, amount: Int)

val tl = List(
  Trans("a", "b", 30), 
  Trans("a", "c", 40),
  Trans("b", "c", 10),
  Trans("b", "a", 25),
  Trans("c", "a", 15)
)

tl foldMap {
    case Trans(from, to, am) => Map(from -> (am, 0), to -> (0, am))
}

答案 1 :(得分:2)

你不需要scalaz。 。 我想,你要找的是import tkinter as tk import sys from tkinter import messagebox name=("user") password=("python3") def login_in(): if entry1.get() == name and entry2.get() == password: root.deiconify() log.destroy() else: messagebox.showerror("error","login Failed") entry1.set("") # This clears entry1 entry2.set("") # this clears entry2 def close(): log.destroy() #Removes toplevel window root.destroy() #Removes root window sys.exit() #Ends the script def session_end(): messagebox.showinfo("session expired","kindly login again") def continue_session(): root.deiconify() root=tk.Tk() log = tk.Toplevel() # root.geometry("350x350") log.geometry("200x200") entry1 = tk.Entry(log) #Username entry entry2 = tk.Entry(log) #Password entry check = tk.Checkbutton(log,text="keep me login",command=continue_session)#root should stay when you tick checkbutton button1 = tk.Button(log, text="Login", command=login_in) #Login button button2 = tk.Button(log, text="Cancel", command=close) #Cancel button label1 = tk.Label(root, text="This main ui after being idle for 5 minutes \n You need to login for the main ui to open") entry1.pack() entry2.pack() check.pack() button1.pack() button2.pack() label1.pack() root.withdraw() root.after(5000,session_end()) root.mainloop()

import tkinter as tk
import sys

name=("user")
password=("python3")

after_id=None

def reset_timer(event=None):
    global after_id
    if after_id is not None:
        root.after_cancel(after_id)
        after_id = root.after(300000,session_end)


def login_in():
    if entry1.get() == name and entry2.get() == password:
        root.deiconify()
        log.destroy()
    else:
        messagebox.showerror("error","login Failed")


def close():
    log.destroy() #Removes toplevel window
    root.destroy() #Removes  root window
    sys.exit() #Ends the script


def session_end():
    messagebox.showinfo("session expired","kindly login again")

def continue_session():
    if after_id is not None:
    root.deiconify()


def print_some():
    print("This is idle timeout")


root=tk.Tk()
log = tk.Toplevel() #

root.geometry("350x350")
log.geometry("200x200")

entry1 = tk.Entry(log) #Username entry
entry2 = tk.Entry(log) #Password entry
check = tk.Checkbutton(log,text="keep me 
login",command=continue_session)#root should stay when you tick checkbutton
button1 = tk.Button(log, text="Login", command=login_in) #Login button
button2 = tk.Button(log, text="Cancel", command=close) #Cancel button
label1 = tk.Label(root, text="This main ui after being idle for 5 minutes \n 
You need to login for the main ui\to open")
print_button = tk.Button(root,text="print",command=print_some).pack()


entry1.pack()
entry2.pack()
check.pack()
button1.pack()
button2.pack()
label1.pack()

root.withdraw()
root.bind_all("<Any-KeyPress>",reset_timer)
root.bind_all("<Any-ButtonPress>",reset_timer)
root.mainloop()

答案 2 :(得分:1)

这似乎只能在列表中进行一次遍历。

tl.foldLeft(Map.empty[String,(Int,Int)].withDefaultValue((0,0))){
  case (m,Trans(from,to,amount)) =>
    val (fromA, fromB) = m(from)
    val (toA, toB) = m(to)
    m + (from -> (fromA+amount, fromB)) + (to -> (toA, toB+amount))
}
//res0: Map[String,(Int, Int)] = Map(a -> (70,40), b -> (35,30), c -> (15,50))

希望你能为中间变量找到更好的名字。