Update all new Tasks
This commit is contained in:
parent
00a190b0a6
commit
91df62d461
5697 changed files with 93386 additions and 804 deletions
38
Task/Hash-join/00DESCRIPTION
Normal file
38
Task/Hash-join/00DESCRIPTION
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
The classic [[wp:Hash Join|hash join]] algorithm for an inner join of two relations has the following steps:
|
||||
<ul>
|
||||
<li>Hash phase: Create a hash table for one of the two relations by applying a hash
|
||||
function to the join attribute of each row. Ideally we should create a hash table for the
|
||||
smaller relation, thus optimizing for creation time and memory size of the hash table.</li>
|
||||
<li>Join phase: Scan the larger relation and find the relevant rows by looking in the
|
||||
hash table created before.</li>
|
||||
</ul>
|
||||
|
||||
The algorithm is as follows:
|
||||
|
||||
'''for each''' tuple ''s'' '''in''' ''S'' '''do'''
|
||||
'''let''' ''h'' = hash on join attributes ''s''(b)
|
||||
'''place''' ''s'' '''in''' hash table ''S<sub>h</sub>'' '''in''' bucket '''keyed by''' hash value ''h''
|
||||
'''for each''' tuple ''r'' '''in''' ''R'' '''do'''
|
||||
'''let''' ''h'' = hash on join attributes ''r''(a)
|
||||
'''if''' ''h'' indicates a nonempty bucket (''B'') of hash table ''S<sub>h</sub>''
|
||||
'''if''' ''h'' matches any ''s'' in ''B''
|
||||
'''concatenate''' ''r'' and ''s''
|
||||
'''place''' relation in ''Q''
|
||||
|
||||
'''Task:''' implement the Hash Join algorithm and show the result of joining two tables with it.
|
||||
You should use your implementation to show the joining of these tables:
|
||||
<table><tr><td><table border>
|
||||
<tr><th>Age</th><th>Name</th></tr>
|
||||
<tr><td>27</td><td>Jonah</td></tr>
|
||||
<tr><td>18</td><td>Alan</td></tr>
|
||||
<tr><td>28</td><td>Glory</td></tr>
|
||||
<tr><td>18</td><td>Popeye</td></tr>
|
||||
<tr><td>28</td><td>Alan</td></tr>
|
||||
</table></td><td><table border>
|
||||
<tr><th>Name</th><th>Nemesis</th></tr>
|
||||
<tr><td>Jonah</td><td>Whales</td></tr>
|
||||
<tr><td>Jonah</td><td>Spiders</td></tr>
|
||||
<tr><td>Alan</td><td>Ghosts</td></tr>
|
||||
<tr><td>Alan</td><td>Zombies</td></tr>
|
||||
<tr><td>Glory</td><td>Buffy</td></tr>
|
||||
</table></td></tr></table>
|
||||
57
Task/Hash-join/Bracmat/hash-join.bracmat
Normal file
57
Task/Hash-join/Bracmat/hash-join.bracmat
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
( (27.Jonah)
|
||||
(18.Alan)
|
||||
(28.Glory)
|
||||
(18.Popeye)
|
||||
(28.Alan)
|
||||
: ?table-A
|
||||
& (Jonah.Whales)
|
||||
(Jonah.Spiders)
|
||||
(Alan.Ghosts)
|
||||
(Alan.Zombies)
|
||||
(Glory.Buffy)
|
||||
: ?table-B
|
||||
& new$hash:?H
|
||||
& !table-A:? [?lenA
|
||||
& !table-B:? [?lenB
|
||||
& ( join
|
||||
= smalltab bigtab smallschema bigschema joinschema
|
||||
, key val val2 keyval2
|
||||
. !arg
|
||||
: (?smalltab.?bigtab.(=?smallschema.?bigschema.?joinschema))
|
||||
& :?rel
|
||||
& !(
|
||||
' ( whl
|
||||
' ( !smalltab:$smallschema ?smalltab
|
||||
& (H..insert)$(!key.!val)
|
||||
)
|
||||
& whl
|
||||
' ( !bigtab:$bigschema ?bigtab
|
||||
& ( (H..find)$!key:?keyval2
|
||||
& whl
|
||||
' ( !keyval2:(?key.?val2) ?keyval2
|
||||
& $joinschema !rel:?rel
|
||||
)
|
||||
|
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
& !rel
|
||||
)
|
||||
& out
|
||||
$ ( join
|
||||
$ ( !lenA:~<!lenB
|
||||
& ( !table-B
|
||||
. !table-A
|
||||
. (
|
||||
= (?key.?val).(?val.?key).!val.!key.!val2
|
||||
)
|
||||
)
|
||||
| ( !table-A
|
||||
. !table-B
|
||||
. (=(?val.?key).(?key.?val).!val2.!key.!val)
|
||||
)
|
||||
)
|
||||
)
|
||||
&
|
||||
);
|
||||
100
Task/Hash-join/C-sharp/hash-join.cs
Normal file
100
Task/Hash-join/C-sharp/hash-join.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace HashJoin
|
||||
{
|
||||
public class AgeName
|
||||
{
|
||||
public AgeName(byte age, string name)
|
||||
{
|
||||
Age = age;
|
||||
Name = name;
|
||||
}
|
||||
public byte Age { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
|
||||
public class NameNemesis
|
||||
{
|
||||
public NameNemesis(string name, string nemesis)
|
||||
{
|
||||
Name = name;
|
||||
Nemesis = nemesis;
|
||||
}
|
||||
public string Name { get; private set; }
|
||||
public string Nemesis { get; private set; }
|
||||
}
|
||||
|
||||
public class DataContext
|
||||
{
|
||||
public DataContext()
|
||||
{
|
||||
AgeName = new List<AgeName>();
|
||||
NameNemesis = new List<NameNemesis>();
|
||||
}
|
||||
public List<AgeName> AgeName { get; set; }
|
||||
public List<NameNemesis> NameNemesis { get; set; }
|
||||
}
|
||||
|
||||
public class AgeNameNemesis
|
||||
{
|
||||
public AgeNameNemesis(byte age, string name, string nemesis)
|
||||
{
|
||||
Age = age;
|
||||
Name = name;
|
||||
Nemesis = nemesis;
|
||||
}
|
||||
public byte Age { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Nemesis { get; private set; }
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
var data = GetData();
|
||||
var result = ExecuteHashJoin(data);
|
||||
WriteResultToConsole(result);
|
||||
}
|
||||
|
||||
private static void WriteResultToConsole(List<AgeNameNemesis> result)
|
||||
{
|
||||
result.ForEach(ageNameNemesis => Console.WriteLine("Age: {0}, Name: {1}, Nemesis: {2}",
|
||||
ageNameNemesis.Age, ageNameNemesis.Name, ageNameNemesis.Nemesis));
|
||||
}
|
||||
|
||||
private static List<AgeNameNemesis> ExecuteHashJoin(DataContext data)
|
||||
{
|
||||
return (data.AgeName.Join(data.NameNemesis,
|
||||
ageName => ageName.Name, nameNemesis => nameNemesis.Name,
|
||||
(ageName, nameNemesis) => new AgeNameNemesis(ageName.Age, ageName.Name, nameNemesis.Nemesis)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static DataContext GetData()
|
||||
{
|
||||
var context = new DataContext();
|
||||
|
||||
context.AgeName.AddRange(new [] {
|
||||
new AgeName(27, "Jonah"),
|
||||
new AgeName(18, "Alan"),
|
||||
new AgeName(28, "Glory"),
|
||||
new AgeName(18, "Popeye"),
|
||||
new AgeName(28, "Alan")
|
||||
});
|
||||
|
||||
context.NameNemesis.AddRange(new[]
|
||||
{
|
||||
new NameNemesis("Jonah", "Whales"),
|
||||
new NameNemesis("Jonah", "Spiders"),
|
||||
new NameNemesis("Alan", "Ghosts"),
|
||||
new NameNemesis("Alan", "Zombies"),
|
||||
new NameNemesis("Glory", "Buffy")
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Task/Hash-join/Clojure/hash-join.clj
Normal file
20
Task/Hash-join/Clojure/hash-join.clj
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
(defn hash-join [table1 col1 table2 col2]
|
||||
(let [hashed (group-by col1 table1)]
|
||||
(flatten
|
||||
(for [r table2]
|
||||
(for [s (hashed (col2 r))]
|
||||
(merge s r))))))
|
||||
|
||||
(def s '({:age 27 :name "Jonah"}
|
||||
{:age 18 :name "Alan"}
|
||||
{:age 28 :name "Glory"}
|
||||
{:age 18 :name "Popeye"}
|
||||
{:age 28 :name "Alan"}))
|
||||
|
||||
(def r '({:nemesis "Whales" :name "Jonah"}
|
||||
{:nemesis "Spiders" :name "Jonah"}
|
||||
{:nemesis "Ghosts" :name "Alan"}
|
||||
{:nemesis "Zombies" :name "Alan"}
|
||||
{:nemesis "Buffy" :name "Glory"}))
|
||||
|
||||
(pprint (sort-by :name (hash-join s :name r :name)))
|
||||
17
Task/Hash-join/Common-Lisp/hash-join.lisp
Normal file
17
Task/Hash-join/Common-Lisp/hash-join.lisp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(defparameter *table-A* '((27 "Jonah") (18 "Alan") (28 "Glory") (18 "Popeye") (28 "Alan")))
|
||||
|
||||
(defparameter *table-B* '(("Jonah" "Whales") ("Jonah" "Spiders") ("Alan" "Ghosts") ("Alan" "Zombies") ("Glory" "Buffy")))
|
||||
|
||||
;; Hash phase
|
||||
(defparameter *hash-table* (make-hash-table :test #'equal))
|
||||
|
||||
(loop for (i r) in *table-A*
|
||||
for value = (gethash r *hash-table* (list nil)) do
|
||||
(setf (gethash r *hash-table*) value)
|
||||
(push (list i r) (first value)))
|
||||
|
||||
;; Join phase
|
||||
(loop for (i r) in *table-B* do
|
||||
(let ((val (car (gethash i *hash-table*))))
|
||||
(loop for (a b) in val do
|
||||
(format t "{~a ~a} {~a ~a}~%" a b i r))))
|
||||
35
Task/Hash-join/D/hash-join.d
Normal file
35
Task/Hash-join/D/hash-join.d
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import std.stdio, std.typecons;
|
||||
|
||||
auto hashJoin(size_t index1, size_t index2, T1, T2)
|
||||
(in T1[] table1, in T2[] table2) pure /*nothrow*/ @safe
|
||||
if (is(typeof(T1.init[index1]) == typeof(T2.init[index2]))) {
|
||||
// Hash phase.
|
||||
T1[][typeof(T1.init[index1])] h;
|
||||
foreach (const s; table1)
|
||||
h[s[index1]] ~= s;
|
||||
|
||||
// Join phase.
|
||||
Tuple!(const T1, const T2)[] result;
|
||||
foreach (const r; table2)
|
||||
foreach (const s; h.get(r[index2], null)) // Not nothrow.
|
||||
result ~= tuple(s, r);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void main() {
|
||||
alias T = tuple;
|
||||
immutable table1 = [T(27, "Jonah"),
|
||||
T(18, "Alan"),
|
||||
T(28, "Glory"),
|
||||
T(18, "Popeye"),
|
||||
T(28, "Alan")];
|
||||
immutable table2 = [T("Jonah", "Whales"),
|
||||
T("Jonah", "Spiders"),
|
||||
T("Alan", "Ghosts"),
|
||||
T("Alan", "Zombies"),
|
||||
T("Glory", "Buffy")];
|
||||
|
||||
foreach (const row; hashJoin!(1, 0)(table1, table2))
|
||||
writefln("(%s, %5s) (%5s, %7s)", row[0][], row[1][]);
|
||||
}
|
||||
19
Task/Hash-join/Deja-Vu/hash-join.djv
Normal file
19
Task/Hash-join/Deja-Vu/hash-join.djv
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
hashJoin table1 index1 table2 index2:
|
||||
local :h {}
|
||||
# hash phase
|
||||
for s in table1:
|
||||
local :key s! index1
|
||||
if not has h key:
|
||||
set-to h key []
|
||||
push-to h! key s
|
||||
# join phase
|
||||
[]
|
||||
for r in table2:
|
||||
for s in copy h! r! index2:
|
||||
push-through swap [ s r ]
|
||||
|
||||
local :table1 [ [ 27 "Jonah" ] [ 18 "Alan" ] [ 28 "Glory" ] [ 18 "Popeye" ] [ 28 "Alan" ] ]
|
||||
local :table2 [ [ "Jonah" "Whales" ] [ "Jonah" "Spiders" ] [ "Alan" "Ghosts" ] [ "Alan" "Zombies" ] [ "Glory" "Buffy" ] ]
|
||||
|
||||
for row in hashJoin table1 1 table2 0:
|
||||
!. row
|
||||
17
Task/Hash-join/Erlang/hash-join.erl
Normal file
17
Task/Hash-join/Erlang/hash-join.erl
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
-module( hash_join ).
|
||||
|
||||
-export( [task/0] ).
|
||||
|
||||
task() ->
|
||||
Table_1 = [{27, "Jonah"}, {18, "Alan"}, {28, "Glory"}, {18, "Popeye"}, {28, "Alan"}],
|
||||
Table_2 = [{"Jonah", "Whales"}, {"Jonah", "Spiders"}, {"Alan", "Ghosts"}, {"Alan", "Zombies"}, {"Glory", "Buffy"}],
|
||||
Dict = lists:foldl( fun dict_append/2, dict:new(), Table_1 ),
|
||||
lists:flatten( [dict_find( X, Dict ) || X <- Table_2] ).
|
||||
|
||||
|
||||
dict_append( {Key, Value}, Acc ) -> dict:append( Value, {Key, Value}, Acc ).
|
||||
|
||||
dict_find( {Key, Value}, Dict ) -> dict_find( dict:find(Key, Dict), Key, Value ).
|
||||
|
||||
dict_find( error, _Key, _Value ) -> [];
|
||||
dict_find( {ok, Values}, Key, Value ) -> [{X, {Key, Value}} || X <- Values].
|
||||
31
Task/Hash-join/Go/hash-join.go
Normal file
31
Task/Hash-join/Go/hash-join.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
tableA := []struct {
|
||||
value int
|
||||
key string
|
||||
}{
|
||||
{27, "Jonah"}, {18, "Alan"}, {28, "Glory"}, {18, "Popeye"},
|
||||
{28, "Alan"},
|
||||
}
|
||||
tableB := []struct {
|
||||
key string
|
||||
value string
|
||||
}{
|
||||
{"Jonah", "Whales"}, {"Jonah", "Spiders"},
|
||||
{"Alan", "Ghosts"}, {"Alan", "Zombies"}, {"Glory", "Buffy"},
|
||||
}
|
||||
// hash phase
|
||||
h := map[string][]int{}
|
||||
for i, r := range tableA {
|
||||
h[r.key] = append(h[r.key], i)
|
||||
}
|
||||
// join phase
|
||||
for _, x := range tableB {
|
||||
for _, a := range h[x.key] {
|
||||
fmt.Println(tableA[a], x)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Task/Hash-join/Groovy/hash-join-1.groovy
Normal file
15
Task/Hash-join/Groovy/hash-join-1.groovy
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
def hashJoin(table1, col1, table2, col2) {
|
||||
|
||||
def hashed = table1.groupBy { s -> s[col1] }
|
||||
|
||||
def q = [] as Set
|
||||
|
||||
table2.each { r ->
|
||||
def join = hashed[r[col2]]
|
||||
join.each { s ->
|
||||
q << s.plus(r)
|
||||
}
|
||||
}
|
||||
|
||||
q
|
||||
}
|
||||
8
Task/Hash-join/Groovy/hash-join-2.groovy
Normal file
8
Task/Hash-join/Groovy/hash-join-2.groovy
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
def hashJoin(table1, col1, table2, col2) {
|
||||
|
||||
def hashed = table1.groupBy { s -> s[col1] }
|
||||
|
||||
table2.collect { r ->
|
||||
hashed[r[col2]].collect { s -> s.plus(r) }
|
||||
}.flatten()
|
||||
}
|
||||
13
Task/Hash-join/Groovy/hash-join-3.groovy
Normal file
13
Task/Hash-join/Groovy/hash-join-3.groovy
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
def s = [[age: 27, name: 'Jonah'],
|
||||
[age: 18, name: 'Alan'],
|
||||
[age: 28, name: 'Glory'],
|
||||
[age: 18, name: 'Popeye'],
|
||||
[age: 28, name: 'Alan']]
|
||||
|
||||
def r = [[name: 'Jonah', nemesis: 'Whales'],
|
||||
[name: 'Jonah', nemesis: 'Spiders'],
|
||||
[name: 'Alan', nemesis: 'Ghosts'],
|
||||
[name: 'Alan', nemesis: 'Zombies'],
|
||||
[name: 'Glory', nemesis: 'Buffy']]
|
||||
|
||||
hashJoin(s, "name", r, "name").sort {it.name}.each { println it }
|
||||
28
Task/Hash-join/Haskell/hash-join-1.hs
Normal file
28
Task/Hash-join/Haskell/hash-join-1.hs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{-# LANGUAGE LambdaCase, TupleSections #-}
|
||||
import qualified Data.HashTable.ST.Basic as H
|
||||
import Data.Hashable
|
||||
import Control.Monad.ST
|
||||
import Control.Monad
|
||||
import Data.STRef
|
||||
|
||||
hashJoin :: (Eq k, Hashable k) =>
|
||||
[t] -> (t -> k) -> [a] -> (a -> k) -> [(t, a)]
|
||||
hashJoin xs fx ys fy = runST $ do
|
||||
l <- newSTRef []
|
||||
ht <- H.new
|
||||
forM_ ys $ \y -> H.insert ht (fy y) =<<
|
||||
(H.lookup ht (fy y) >>= \case
|
||||
Nothing -> return [y]
|
||||
Just v -> return (y:v))
|
||||
forM_ xs $ \x -> do
|
||||
H.lookup ht (fx x) >>= \case
|
||||
Nothing -> return ()
|
||||
Just v -> modifySTRef' l ((map (x,) v) ++)
|
||||
readSTRef l
|
||||
|
||||
test = mapM_ print $ hashJoin
|
||||
[(1, "Jonah"), (2, "Alan"), (3, "Glory"), (4, "Popeye")]
|
||||
snd
|
||||
[("Jonah", "Whales"), ("Jonah", "Spiders"),
|
||||
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
|
||||
fst
|
||||
18
Task/Hash-join/Haskell/hash-join-2.hs
Normal file
18
Task/Hash-join/Haskell/hash-join-2.hs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{-# LANGUAGE TupleSections #-}
|
||||
import qualified Data.Map as M
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Control.Applicative
|
||||
|
||||
mapJoin xs fx ys fy = joined
|
||||
where yMap = foldl' f M.empty ys
|
||||
f m y = M.insertWith (++) (fy y) [y] m
|
||||
joined = concat . catMaybes .
|
||||
map (\x -> map (x,) <$> M.lookup (fx x) yMap) $ xs
|
||||
|
||||
test = mapM_ print $ mapJoin
|
||||
[(1, "Jonah"), (2, "Alan"), (3, "Glory"), (4, "Popeye")]
|
||||
snd
|
||||
[("Jonah", "Whales"), ("Jonah", "Spiders"),
|
||||
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
|
||||
fst
|
||||
15
Task/Hash-join/J/hash-join-1.j
Normal file
15
Task/Hash-join/J/hash-join-1.j
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
table1=: ;:;._2(0 :0)
|
||||
27 Jonah
|
||||
18 Alan
|
||||
28 Glory
|
||||
18 Popeye
|
||||
28 Alan
|
||||
)
|
||||
|
||||
table2=: ;:;._2(0 :0)
|
||||
Jonah Whales
|
||||
Jonah Spiders
|
||||
Alan Ghosts
|
||||
Alan Zombies
|
||||
Glory Buffy
|
||||
)
|
||||
9
Task/Hash-join/J/hash-join-2.j
Normal file
9
Task/Hash-join/J/hash-join-2.j
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
hash=: ]
|
||||
dojoin=:3 :0
|
||||
c1=. {.{.y
|
||||
c2=. (1 {"1 y) -. a:
|
||||
c3=. (2 {"1 y) -. a:
|
||||
>{c1;c2;<c3
|
||||
)
|
||||
|
||||
JOIN=: ; -.&a: ,/each(hash@{."1 <@dojoin/. ]) (1 1 0&#inv@|."1 table1), 1 0 1#inv"1 table2
|
||||
16
Task/Hash-join/J/hash-join-3.j
Normal file
16
Task/Hash-join/J/hash-join-3.j
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
JOIN
|
||||
┌─────┬──┬───────┐
|
||||
│Jonah│27│Whales │
|
||||
├─────┼──┼───────┤
|
||||
│Jonah│27│Spiders│
|
||||
├─────┼──┼───────┤
|
||||
│Alan │18│Ghosts │
|
||||
├─────┼──┼───────┤
|
||||
│Alan │18│Zombies│
|
||||
├─────┼──┼───────┤
|
||||
│Alan │28│Ghosts │
|
||||
├─────┼──┼───────┤
|
||||
│Alan │28│Zombies│
|
||||
├─────┼──┼───────┤
|
||||
│Glory│28│Buffy │
|
||||
└─────┴──┴───────┘
|
||||
10
Task/Hash-join/Mathematica/hash-join.math
Normal file
10
Task/Hash-join/Mathematica/hash-join.math
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
hashJoin[table1_List,table1colindex_Integer,table2_List,table2colindex_Integer]:=Module[{h,f,t1,t2,tmp},
|
||||
t1=If[table1colindex != 1,table1[[All,Prepend[Delete[Range@Length@table1[[1]],table1colindex],table1colindex]]],table1];
|
||||
t2=If[table2colindex != 1, table2[[All,Prepend[Delete[Range@Length@table2[[1]],table2colindex],table2colindex]]],table2];
|
||||
|
||||
If[Length[t1]>Length[t2],tmp=t1;t1=t2;t2=tmp;];
|
||||
h= GroupBy[t1,First];
|
||||
f[{a_,b_List}]:={a,#}&/@b;
|
||||
Partition[Flatten[Map[f,{#[[2;;]],h[#[[1]]]}&/@t2
|
||||
]],Length[t1[[1]]]+Length[t2[[1]]]-1]
|
||||
];
|
||||
8
Task/Hash-join/OCaml/hash-join.ocaml
Normal file
8
Task/Hash-join/OCaml/hash-join.ocaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
let hash_join table1 f1 table2 f2 =
|
||||
let h = Hashtbl.create 42 in
|
||||
(* hash phase *)
|
||||
List.iter (fun s ->
|
||||
Hashtbl.add h (f1 s) s) table1;
|
||||
(* join phase *)
|
||||
List.concat (List.map (fun r ->
|
||||
List.map (fun s -> s, r) (Hashtbl.find_all h (f2 r))) table2)
|
||||
94
Task/Hash-join/Oberon-2/hash-join.oberon-2
Normal file
94
Task/Hash-join/Oberon-2/hash-join.oberon-2
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
MODULE HashJoin;
|
||||
IMPORT
|
||||
ADT:Dictionary,
|
||||
ADT:LinkedList,
|
||||
NPCT:Tools,
|
||||
Object,
|
||||
Object:Boxed,
|
||||
Out;
|
||||
TYPE
|
||||
(* Some Aliases *)
|
||||
Age= Boxed.LongInt;
|
||||
Name= STRING;
|
||||
Nemesis= STRING;
|
||||
|
||||
(* Generic Tuple *)
|
||||
Tuple(E1: Object.Object; E2: Object.Object) = POINTER TO TupleDesc(E1,E2);
|
||||
TupleDesc(E1: Object.Object; E2: Object.Object) = RECORD
|
||||
(Object.ObjectDesc)
|
||||
_1: E1;
|
||||
_2: E2;
|
||||
END;
|
||||
|
||||
(* Relations *)
|
||||
RelationA = ARRAY 5 OF Tuple(Age,Name);
|
||||
RelationB = ARRAY 5 OF Tuple(Name,Nemesis);
|
||||
|
||||
VAR
|
||||
tableA: RelationA;
|
||||
tableB: RelationB;
|
||||
dict: Dictionary.Dictionary(Name,LinkedList.LinkedList(Age));
|
||||
ll: LinkedList.LinkedList(Age);
|
||||
|
||||
PROCEDURE (t: Tuple(E1, E2)) INIT*(e1: E1; e2: E2);
|
||||
BEGIN
|
||||
t._1 := e1;
|
||||
t._2 := e2;
|
||||
END INIT;
|
||||
|
||||
PROCEDURE DoHashPhase(t: RelationA;VAR dict: Dictionary.Dictionary(Name,LinkedList.LinkedList(Age)));
|
||||
VAR
|
||||
i: INTEGER;
|
||||
ll: LinkedList.LinkedList(Age);
|
||||
BEGIN
|
||||
i := 0;
|
||||
WHILE (i < LEN(t)) & (t[i] # NIL) DO
|
||||
IF (dict.HasKey(t[i]._2)) THEN
|
||||
ll := dict.Get(t[i]._2);
|
||||
ELSE
|
||||
ll := NEW(LinkedList.LinkedList(Age));
|
||||
dict.Set(t[i]._2,ll)
|
||||
END;
|
||||
ll.Append(t[i]._1);
|
||||
INC(i)
|
||||
END
|
||||
END DoHashPhase;
|
||||
|
||||
PROCEDURE DoJoinPhase(t: RelationB; dict: Dictionary.Dictionary(Name,LinkedList.LinkedList(Age)));
|
||||
VAR
|
||||
i: INTEGER;
|
||||
age: Age;
|
||||
iterll: LinkedList.Iterator(Age);
|
||||
BEGIN
|
||||
FOR i := 0 TO LEN(t) - 1 DO
|
||||
ll := dict.Get(t[i]._1);
|
||||
iterll := ll.GetIterator(NIL);
|
||||
WHILE iterll.HasNext() DO
|
||||
age := iterll.Next();
|
||||
Out.LongInt(age.value,4);
|
||||
Out.Object(Tools.AdjustRight(t[i]._1,10));
|
||||
Out.Object(Tools.AdjustRight(t[i]._2,10));Out.Ln
|
||||
END
|
||||
END
|
||||
END DoJoinPhase;
|
||||
|
||||
BEGIN
|
||||
(* tableA initialization *)
|
||||
tableA[0] := NEW(Tuple(Age,Name),NEW(Age,27),"Jonah");
|
||||
tableA[1] := NEW(Tuple(Age,Name),NEW(Age,18),"Alan");
|
||||
tableA[2] := NEW(Tuple(Age,Name),NEW(Age,28),"Glory");
|
||||
tableA[3] := NEW(Tuple(Age,Name),NEW(Age,18),"Popeye");
|
||||
tableA[4] := NEW(Tuple(Age,Name),NEW(Age,28),"Alan");
|
||||
|
||||
(* tableB initialization *)
|
||||
tableB[0] := NEW(Tuple(Name,Nemesis),"Jonah","Whales");
|
||||
tableB[1] := NEW(Tuple(Name,Nemesis),"Jonah","Spiders");
|
||||
tableB[2] := NEW(Tuple(Name,Nemesis),"Alan","Ghost");
|
||||
tableB[3] := NEW(Tuple(Name,Nemesis),"Alan","Zombies");
|
||||
tableB[4] := NEW(Tuple(Name,Nemesis),"Glory","Buffy");
|
||||
|
||||
dict := NEW(Dictionary.Dictionary(Name,LinkedList.LinkedList(Age)));
|
||||
|
||||
DoHashPhase(tableA,dict);
|
||||
DoJoinPhase(tableB,dict);
|
||||
END HashJoin.
|
||||
27
Task/Hash-join/PHP/hash-join.php
Normal file
27
Task/Hash-join/PHP/hash-join.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
function hashJoin($table1, $index1, $table2, $index2) {
|
||||
// hash phase
|
||||
foreach ($table1 as $s)
|
||||
$h[$s[$index1]][] = $s;
|
||||
// join phase
|
||||
foreach ($table2 as $r)
|
||||
foreach ($h[$r[$index2]] as $s)
|
||||
$result[] = array($s, $r);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$table1 = array(array(27, "Jonah"),
|
||||
array(18, "Alan"),
|
||||
array(28, "Glory"),
|
||||
array(18, "Popeye"),
|
||||
array(28, "Alan"));
|
||||
$table2 = array(array("Jonah", "Whales"),
|
||||
array("Jonah", "Spiders"),
|
||||
array("Alan", "Ghosts"),
|
||||
array("Alan", "Zombies"),
|
||||
array("Glory", "Buffy"),
|
||||
array("Bob", "foo"));
|
||||
|
||||
foreach (hashJoin($table1, 1, $table2, 0) as $row)
|
||||
print_r($row);
|
||||
?>
|
||||
18
Task/Hash-join/Perl-6/hash-join.pl6
Normal file
18
Task/Hash-join/Perl-6/hash-join.pl6
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
my @A = [1, "Jonah"],
|
||||
[2, "Alan"],
|
||||
[3, "Glory"],
|
||||
[4, "Popeye"];
|
||||
|
||||
my @B = ["Jonah", "Whales"],
|
||||
["Jonah", "Spiders"],
|
||||
["Alan", "Ghosts"],
|
||||
["Alan", "Zombies"],
|
||||
["Glory", "Buffy"];
|
||||
|
||||
sub hash-join(@a, &a, @b, &b) {
|
||||
my %hash{Any};
|
||||
%hash{.&a} = $_ for @a;
|
||||
([%hash{.&b} // next, $_] for @b);
|
||||
}
|
||||
|
||||
.perl.say for hash-join @A, *.[1], @B, *.[0];
|
||||
30
Task/Hash-join/Perl/hash-join.pl
Normal file
30
Task/Hash-join/Perl/hash-join.pl
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use Data::Dumper qw(Dumper);
|
||||
|
||||
sub hashJoin {
|
||||
my ($table1, $index1, $table2, $index2) = @_;
|
||||
my %h;
|
||||
# hash phase
|
||||
foreach my $s (@$table1) {
|
||||
push @{ $h{$s->[$index1]} }, $s;
|
||||
}
|
||||
# join phase
|
||||
map { my $r = $_;
|
||||
map [$_, $r], @{ $h{$r->[$index2]} }
|
||||
} @$table2;
|
||||
}
|
||||
|
||||
@table1 = ([27, "Jonah"],
|
||||
[18, "Alan"],
|
||||
[28, "Glory"],
|
||||
[18, "Popeye"],
|
||||
[28, "Alan"]);
|
||||
@table2 = (["Jonah", "Whales"],
|
||||
["Jonah", "Spiders"],
|
||||
["Alan", "Ghosts"],
|
||||
["Alan", "Zombies"],
|
||||
["Glory", "Buffy"]);
|
||||
|
||||
$Data::Dumper::Indent = 0;
|
||||
foreach my $row (hashJoin(\@table1, 1, \@table2, 0)) {
|
||||
print Dumper($row), "\n";
|
||||
}
|
||||
23
Task/Hash-join/Python/hash-join.py
Normal file
23
Task/Hash-join/Python/hash-join.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from collections import defaultdict
|
||||
|
||||
def hashJoin(table1, index1, table2, index2):
|
||||
h = defaultdict(list)
|
||||
# hash phase
|
||||
for s in table1:
|
||||
h[s[index1]].append(s)
|
||||
# join phase
|
||||
return [(s, r) for r in table2 for s in h[r[index2]]]
|
||||
|
||||
table1 = [(27, "Jonah"),
|
||||
(18, "Alan"),
|
||||
(28, "Glory"),
|
||||
(18, "Popeye"),
|
||||
(28, "Alan")]
|
||||
table2 = [("Jonah", "Whales"),
|
||||
("Jonah", "Spiders"),
|
||||
("Alan", "Ghosts"),
|
||||
("Alan", "Zombies"),
|
||||
("Glory", "Buffy")]
|
||||
|
||||
for row in hashJoin(table1, 1, table2, 0):
|
||||
print(row)
|
||||
1
Task/Hash-join/README
Normal file
1
Task/Hash-join/README
Normal file
|
|
@ -0,0 +1 @@
|
|||
Data source: http://rosettacode.org/wiki/Hash_join
|
||||
33
Task/Hash-join/REXX/hash-join.rexx
Normal file
33
Task/Hash-join/REXX/hash-join.rexx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*REXX pgm demonstrates the classic hash join algorithm for 2 relations.*/
|
||||
S. = ; R. =
|
||||
S.1 = 27 'Jonah' ; R.1 = 'Jonah Whales'
|
||||
S.2 = 18 'Alan' ; R.2 = 'Jonah Spiders'
|
||||
S.3 = 28 'Glory' ; R.3 = 'Alan Ghosts'
|
||||
S.4 = 18 'Popeye' ; R.4 = 'Alan Zombies'
|
||||
S.5 = 28 'Alan' ; R.5 = 'Glory Buffy'
|
||||
hash.= /*initialize the hash table. */
|
||||
do #=1 while S.#\==''; parse var S.# age name /*extract info*/
|
||||
hash.name=hash.name # /*build a hash table entry. */
|
||||
end /*#*/ /* [↑] REXX does the heavy work.*/
|
||||
#=#-1 /*adjust for DO loop (#) overage.*/
|
||||
do j=1 while R.j\=='' /*process a nemesis for a name. */
|
||||
parse var R.j x nemesis /*extract name and it's nemesis. */
|
||||
if hash.x=='' then do /*Not in hash? Then a new name.*/
|
||||
#=#+1 /*bump the number of S entries. */
|
||||
S.#=',' x /*add new name to the S table. */
|
||||
hash.x=# /*add new name to the hash table.*/
|
||||
end /* [↑] this DO isn't used today.*/
|
||||
do k=1 for words(hash.x); _=word(hash.x,k) /*get pointer.*/
|
||||
S._=S._ nemesis /*add nemesis──► applicable hash.*/
|
||||
end /*k*/
|
||||
end /*j*/
|
||||
_='─' /*character used for separater. */
|
||||
pad=left('',6-2) /*spacing used in hdr/sep/output.*/
|
||||
say pad center('age',3) pad center('name',20) pad center('nemesis',30)
|
||||
say pad center('───',3) pad center('' ,20,_) pad center('' ,30,_)
|
||||
|
||||
do n=1 for #; parse var S.n age name nems /*get info. */
|
||||
if nems=='' then iterate /*if no nemesis, then don't show.*/
|
||||
say pad right(age,3) pad center(name,20) pad nems /*show an S.*/
|
||||
end /*n*/
|
||||
/*stick a fork in it, we're done.*/
|
||||
29
Task/Hash-join/Racket/hash-join.rkt
Normal file
29
Task/Hash-join/Racket/hash-join.rkt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#lang racket
|
||||
(struct A (age name))
|
||||
(struct B (name nemesis))
|
||||
(struct AB (name age nemesis) #:transparent)
|
||||
|
||||
(define Ages-table
|
||||
(list (A 27 "Jonah") (A 18 "Alan")
|
||||
(A 28 "Glory") (A 18 "Popeye")
|
||||
(A 28 "Alan")))
|
||||
|
||||
(define Nemeses-table
|
||||
(list
|
||||
(B "Jonah" "Whales") (B "Jonah" "Spiders")
|
||||
(B "Alan" "Ghosts") (B "Alan" "Zombies")
|
||||
(B "Glory" "Buffy")))
|
||||
|
||||
;; Hash phase
|
||||
(define name->ages#
|
||||
(for/fold ((rv (hash)))
|
||||
((a (in-list Ages-table)))
|
||||
(match-define (A age name) a)
|
||||
(hash-update rv name (λ (ages) (append ages (list age))) null)))
|
||||
|
||||
;; Join phase
|
||||
(for*/list
|
||||
((b (in-list Nemeses-table))
|
||||
(key (in-value (B-name b)))
|
||||
(age (in-list (hash-ref name->ages# key))))
|
||||
(AB key age (B-nemesis b)))
|
||||
22
Task/Hash-join/Ruby/hash-join.rb
Normal file
22
Task/Hash-join/Ruby/hash-join.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
def hashJoin(table1, index1, table2, index2)
|
||||
# hash phase
|
||||
h = table1.group_by {|s| s[index1]}
|
||||
h.default = []
|
||||
# join phase
|
||||
table2.collect {|r|
|
||||
h[r[index2]].collect {|s| [s, r]}
|
||||
}.flatten(1)
|
||||
end
|
||||
|
||||
table1 = [[27, "Jonah"],
|
||||
[18, "Alan"],
|
||||
[28, "Glory"],
|
||||
[18, "Popeye"],
|
||||
[28, "Alan"]]
|
||||
table2 = [["Jonah", "Whales"],
|
||||
["Jonah", "Spiders"],
|
||||
["Alan", "Ghosts"],
|
||||
["Alan", "Zombies"],
|
||||
["Glory", "Buffy"]]
|
||||
|
||||
hashJoin(table1, 1, table2, 0).each { |row| p row }
|
||||
13
Task/Hash-join/SQL/hash-join-1.sql
Normal file
13
Task/Hash-join/SQL/hash-join-1.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
create table people (age decimal(3), name varchar(16));
|
||||
insert into people (age, name) values (27, 'Jonah');
|
||||
insert into people (age, name) values (18, 'Alan');
|
||||
insert into people (age, name) values (28, 'Glory');
|
||||
insert into people (age, name) values (18, 'Popeye');
|
||||
insert into people (age, name) values (28, 'Alan');
|
||||
|
||||
create table nemesises (name varchar(16), nemesis varchar(16));
|
||||
insert into nemesises (name, nemesis) values ('Jonah', 'Whales');
|
||||
insert into nemesises (name, nemesis) values ('Jonah', 'Spiders');
|
||||
insert into nemesises (name, nemesis) values ('Alan', 'Ghosts');
|
||||
insert into nemesises (name, nemesis) values ('Alan', 'Zombies');
|
||||
insert into nemesises (name, nemesis) values ('Glory', 'Buffy');
|
||||
1
Task/Hash-join/SQL/hash-join-2.sql
Normal file
1
Task/Hash-join/SQL/hash-join-2.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
select * from people p join nemesises n on p.name = n.name
|
||||
19
Task/Hash-join/Scala/hash-join.scala
Normal file
19
Task/Hash-join/Scala/hash-join.scala
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
def join[Type](left: Seq[Seq[Type]], right: Seq[Seq[Type]]) = {
|
||||
val hash = right.groupBy(_.head) withDefaultValue Seq()
|
||||
left.flatMap(cols => hash(cols.last).map(cols ++ _.tail))
|
||||
}
|
||||
|
||||
// Example:
|
||||
|
||||
val table1 = List(List("27", "Jonah"),
|
||||
List("18", "Alan"),
|
||||
List("28", "Glory"),
|
||||
List("18", "Popeye"),
|
||||
List("28", "Alan"))
|
||||
val table2 = List(List("Jonah", "Whales"),
|
||||
List("Jonah", "Spiders"),
|
||||
List("Alan", "Ghosts"),
|
||||
List("Alan", "Zombies"),
|
||||
List("Glory", "Buffy"))
|
||||
|
||||
println(join(table1, table2) mkString "\n")
|
||||
20
Task/Hash-join/Scheme/hash-join.ss
Normal file
20
Task/Hash-join/Scheme/hash-join.ss
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
(use srfi-42)
|
||||
|
||||
(define ages '((27 Jonah) (18 Alan) (28 Glory) (18 Popeye) (28 Alan)))
|
||||
|
||||
(define nemeses '((Jonah Whales) (Jonah Spiders) (Alan Ghosts)
|
||||
(Alan Zombies) (Glory Buffy)
|
||||
(unknown nothing)))
|
||||
|
||||
(define hash (make-hash-table 'equal?))
|
||||
|
||||
(dolist (item ages)
|
||||
(hash-table-push! hash (last item) (car item)))
|
||||
|
||||
(do-ec
|
||||
(: person nemeses)
|
||||
(:let name (car person))
|
||||
(if (hash-table-exists? hash name))
|
||||
(: age (~ hash name))
|
||||
(print (list (list age name)
|
||||
person)))
|
||||
20
Task/Hash-join/TXR/hash-join.txr
Normal file
20
Task/Hash-join/TXR/hash-join.txr
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
@(do
|
||||
(defvar age-name '((27 Jonah)
|
||||
(18 Alan)
|
||||
(28 Glory)
|
||||
(18 Popeye)
|
||||
(28 Alan)))
|
||||
|
||||
(defvar nemesis-name '((Jonah Whales)
|
||||
(Jonah Spiders)
|
||||
(Alan Ghosts)
|
||||
(Alan Zombies)
|
||||
(Glory Buffy)))
|
||||
|
||||
(defun hash-join (left left-key right right-key)
|
||||
(let ((join-hash [group-by left-key left])) ;; hash phase
|
||||
(append-each ((r-entry right)) ;; join phase
|
||||
(collect-each ((l-entry [join-hash [right-key r-entry]]))
|
||||
^(,l-entry ,r-entry)))))
|
||||
|
||||
(format t "~s\n" [hash-join age-name second nemesis-name first]))
|
||||
39
Task/Hash-join/Tcl/hash-join.tcl
Normal file
39
Task/Hash-join/Tcl/hash-join.tcl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package require Tcl 8.6
|
||||
# Only for lmap, which can be replaced with foreach
|
||||
|
||||
proc joinTables {tableA a tableB b} {
|
||||
# Optimisation: if the first table is longer, do in reverse order
|
||||
if {[llength $tableB] < [llength $tableA]} {
|
||||
return [lmap pair [joinTables $tableB $b $tableA $a] {
|
||||
lreverse $pair
|
||||
}]
|
||||
}
|
||||
|
||||
foreach value $tableA {
|
||||
lappend hashmap([lindex $value $a]) [lreplace $value $a $a]
|
||||
#dict version# dict lappend hashmap [lindex $value $a] [lreplace $value $a $a]
|
||||
}
|
||||
set result {}
|
||||
foreach value $tableB {
|
||||
set key [lindex $value $b]
|
||||
if {![info exists hashmap($key)]} continue
|
||||
#dict version# if {![dict exists $hashmap $key]} continue
|
||||
foreach first $hashmap($key) {
|
||||
#dict version# foreach first [dict get $hashmap $key]
|
||||
lappend result [list {*}$first $key {*}[lreplace $value $b $b]]
|
||||
}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
set tableA {
|
||||
{27 "Jonah"} {18 "Alan"} {28 "Glory"} {18 "Popeye"} {28 "Alan"}
|
||||
}
|
||||
set tableB {
|
||||
{"Jonah" "Whales"} {"Jonah" "Spiders"} {"Alan" "Ghosts"} {"Alan" "Zombies"}
|
||||
{"Glory" "Buffy"}
|
||||
}
|
||||
set joined [joinTables $tableA 1 $tableB 0]
|
||||
foreach row $joined {
|
||||
puts $row
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue