defmodule TutorialD do # @spec (list +union+ term) :: maybe_improper_list ## ## row is Dict(columnname, value) ## table is HashSet(row) def union(left,right) do Set.union(left, right) end def minus(left, right) do Set.difference(left, right) end def intersect(left, right) do Set.intersection(left, right) end def where(left, f) do Stream.filter(left, f) |> Enum.into(HashSet.new) end def project(left, attributes) when is_list(attributes) do Stream.map(left, fn(x) -> Dict.take(x, attributes) end) |> Enum.into(HashSet.new) end def fields(left) do Enum.at(left, 0) |> Map.keys end def fnjoin(left, right) do lkset = fields(left) |> Enum.into(HashSet.new) rkset = fields(right) |> Enum.into(HashSet.new) ks = Set.intersection(lkset, rkset) Enum.reduce(left, [], fn(x, acc) -> z = Enum.filter_map(right, fn(y) -> Dict.equal?(Map.take(y, ks), Map.take(x, ks)) end, fn(y) -> Map.merge(x, y) end) case z do [] -> acc [e] -> [e|acc] end end) end defp product(left, right) do Enum.reduce(left, [], fn(x, acc) -> Enum.map(right, &(Dict.merge(x, &1))) |> Enum.into(acc) end) end def join(left, right) do if (Enum.count(left) == 0 or Enum.count(right) == 0) do HashSet.new() else fnjoin(left, right) |> Enum.into(HashSet.new) end end def matching(left, right) do if (Enum.count(left) == 0 or Enum.count(right) == 0) do HashSet.new() else lkset = fields(left) fnjoin(left, right) |> project(lkset) end end def divideby(left, right) do fl = fields(left) fr = fields(right) fd = fl -- fr pleft = project(left, fd) pr = Enum.into(product(pleft, right), HashSet.new) minus(pleft, project(minus(pr, left), fd)) end def rename(left, from, to) do fl = fields(left) Enum.reduce(left, HashSet.new, fn(x, a) -> v = Dict.get(x, from) y = Dict.delete(Dict.put(x, to, v), from) Set.put(a, y) end) end def extend_add(left, fun, x) do Enum.reduce(left, HashSet.new, fn(e, a) -> Set.put(a, Dict.put(e, x, fun.(e))) end) end def update(left, right) do minus(right, left) |> write!() end def write!(left) do IO.inspect [write: left] left end end