September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
61
Task/Hash-join/AWK/hash-join.awk
Normal file
61
Task/Hash-join/AWK/hash-join.awk
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# syntax: GAWK -f HASH_JOIN.AWK [-v debug={0|1}] TABLE_A TABLE_B
|
||||
#
|
||||
# sorting:
|
||||
# PROCINFO["sorted_in"] is used by GAWK
|
||||
# SORTTYPE is used by Thompson Automation's TAWK
|
||||
#
|
||||
BEGIN {
|
||||
FS = ","
|
||||
PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
|
||||
if (ARGC-1 != 2) {
|
||||
print("error: incorrect number of arguments") ; errors++
|
||||
exit # go to END
|
||||
}
|
||||
}
|
||||
{ if (NR == FNR) { # table A
|
||||
if (FNR == 1) {
|
||||
a_head = prefix_column_names("A")
|
||||
next
|
||||
}
|
||||
a_arr[$2][$1] = $0 # [name][age]
|
||||
}
|
||||
if (NR != FNR) { # table B
|
||||
if (FNR == 1) {
|
||||
b_head = prefix_column_names("B")
|
||||
next
|
||||
}
|
||||
b_arr[$1][$2] = $0 # [character][nemesis]
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (errors > 0) { exit(1) }
|
||||
if (debug == 1) {
|
||||
dump_table(a_arr,a_head)
|
||||
dump_table(b_arr,b_head)
|
||||
}
|
||||
printf("%s%s%s\n",a_head,FS,b_head) # table heading
|
||||
for (i in a_arr) {
|
||||
if (i in b_arr) {
|
||||
for (j in a_arr[i]) {
|
||||
for (k in b_arr[i]) {
|
||||
print(a_arr[i][j] FS b_arr[i][k]) # join table A & table B
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
function dump_table(arr,heading, i,j) {
|
||||
printf("%s\n",heading)
|
||||
for (i in arr) {
|
||||
for (j in arr[i]) {
|
||||
printf("%s\n",arr[i][j])
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
function prefix_column_names(p, tmp) {
|
||||
tmp = p "." $0
|
||||
gsub(/,/,"&" p ".",tmp)
|
||||
return(tmp)
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
use framework "Foundation" -- Yosemite onwards, for record-handling functions
|
||||
|
||||
-- HASH JOIN -----------------------------------------------------------------
|
||||
|
||||
-- hashJoin :: [Record] -> [Record] -> String -> [Record]
|
||||
on hashJoin(tblA, tblB, strJoin)
|
||||
set {jA, jB} to splitOn("=", strJoin)
|
||||
|
||||
script instanceOfjB
|
||||
on lambda(a, x)
|
||||
on |λ|(a, x)
|
||||
set strID to keyValue(x, jB)
|
||||
|
||||
set maybeInstances to keyValue(a, strID)
|
||||
|
|
@ -14,32 +16,32 @@ on hashJoin(tblA, tblB, strJoin)
|
|||
else
|
||||
updatedRecord(a, strID, [x])
|
||||
end if
|
||||
end lambda
|
||||
end |λ|
|
||||
end script
|
||||
|
||||
set M to foldl(instanceOfjB, {name:"multiMap"}, tblB)
|
||||
|
||||
script joins
|
||||
on lambda(a, x)
|
||||
on |λ|(a, x)
|
||||
set matches to keyValue(M, keyValue(x, jA))
|
||||
if matches is not missing value then
|
||||
script concat
|
||||
on lambda(row)
|
||||
on |λ|(row)
|
||||
x & row
|
||||
end lambda
|
||||
end |λ|
|
||||
end script
|
||||
|
||||
a & map(concat, matches)
|
||||
else
|
||||
a
|
||||
end if
|
||||
end lambda
|
||||
end |λ|
|
||||
end script
|
||||
|
||||
foldl(joins, {}, tblA)
|
||||
end hashJoin
|
||||
|
||||
-- TEST
|
||||
-- TEST ----------------------------------------------------------------------
|
||||
on run
|
||||
set lstA to [¬
|
||||
{age:27, |name|:"Jonah"}, ¬
|
||||
|
|
@ -60,12 +62,13 @@ on run
|
|||
end run
|
||||
|
||||
|
||||
-- RECORD PRIMITIVES
|
||||
-- RECORD FUNCTIONS ----------------------------------------------------------
|
||||
|
||||
-- keyValue :: String -> Record -> Maybe a
|
||||
on keyValue(rec, strKey)
|
||||
set ca to current application
|
||||
set v to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
|
||||
set v to (ca's NSDictionary's dictionaryWithDictionary:rec)'s ¬
|
||||
objectForKey:strKey
|
||||
if v is not missing value then
|
||||
item 1 of ((ca's NSArray's arrayWithObject:v) as list)
|
||||
else
|
||||
|
|
@ -82,7 +85,7 @@ on updatedRecord(rec, strKey, varValue)
|
|||
end updatedRecord
|
||||
|
||||
|
||||
-- GENERIC PRIMITIVES
|
||||
-- GENERIC FUNCTIONS ---------------------------------------------------------
|
||||
|
||||
-- foldl :: (a -> b -> a) -> a -> [b] -> a
|
||||
on foldl(f, startValue, xs)
|
||||
|
|
@ -90,7 +93,7 @@ on foldl(f, startValue, xs)
|
|||
set v to startValue
|
||||
set lng to length of xs
|
||||
repeat with i from 1 to lng
|
||||
set v to lambda(v, item i of xs, i, xs)
|
||||
set v to |λ|(v, item i of xs, i, xs)
|
||||
end repeat
|
||||
return v
|
||||
end tell
|
||||
|
|
@ -102,20 +105,12 @@ on map(f, xs)
|
|||
set lng to length of xs
|
||||
set lst to {}
|
||||
repeat with i from 1 to lng
|
||||
set end of lst to lambda(item i of xs, i, xs)
|
||||
set end of lst to |λ|(item i of xs, i, xs)
|
||||
end repeat
|
||||
return lst
|
||||
end tell
|
||||
end map
|
||||
|
||||
-- splitOn :: Text -> Text -> [Text]
|
||||
on splitOn(strDelim, strMain)
|
||||
set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
|
||||
set lstParts to text items of strMain
|
||||
set my text item delimiters to dlm
|
||||
return lstParts
|
||||
end splitOn
|
||||
|
||||
-- Lift 2nd class handler function into 1st class script wrapper
|
||||
-- mReturn :: Handler -> Script
|
||||
on mReturn(f)
|
||||
|
|
@ -123,7 +118,15 @@ on mReturn(f)
|
|||
f
|
||||
else
|
||||
script
|
||||
property lambda : f
|
||||
property |λ| : f
|
||||
end script
|
||||
end if
|
||||
end mReturn
|
||||
|
||||
-- splitOn :: Text -> Text -> [Text]
|
||||
on splitOn(strDelim, strMain)
|
||||
set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
|
||||
set lstParts to text items of strMain
|
||||
set my text item delimiters to dlm
|
||||
return lstParts
|
||||
end splitOn
|
||||
|
|
|
|||
8
Task/Hash-join/Julia/hash-join-1.julia
Normal file
8
Task/Hash-join/Julia/hash-join-1.julia
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
using DataFrames
|
||||
|
||||
A = DataFrame(Age = [27, 18, 28, 18, 28], Name = ["Jonah", "Alan", "Glory", "Popeye", "Alan"])
|
||||
B = DataFrame(Name = ["Jonah", "Jonah", "Alan", "Alan", "Glory"],
|
||||
Nemesis = ["Whales", "Spiders", "Ghosts", "Zombies", "Buffy"])
|
||||
AB = join(A, B, on = :Name)
|
||||
|
||||
@show A B AB
|
||||
19
Task/Hash-join/Julia/hash-join-2.julia
Normal file
19
Task/Hash-join/Julia/hash-join-2.julia
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
function hashjoin(A::Array, ja::Int, B::Array, jb::Int)
|
||||
M = Dict(t[jb] => filter(l -> l[jb] == t[jb], B) for t in B)
|
||||
return collect([a, b] for a in A for b in get(M, a[ja], ()))
|
||||
end
|
||||
|
||||
table1 = [(27, "Jonah"),
|
||||
(18, "Alan"),
|
||||
(28, "Glory"),
|
||||
(18, "Popeye"),
|
||||
(28, "Alan")]
|
||||
table2 = [("Jonah", "Whales"),
|
||||
("Jonah", "Spiders"),
|
||||
("Alan", "Ghosts"),
|
||||
("Alan", "Zombies"),
|
||||
("Glory", "Buffy")]
|
||||
|
||||
for r in hashjoin(table1, 2, table2, 1)
|
||||
println(r)
|
||||
end
|
||||
39
Task/Hash-join/Kotlin/hash-join.kotlin
Normal file
39
Task/Hash-join/Kotlin/hash-join.kotlin
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
data class A(val age: Int, val name: String)
|
||||
|
||||
data class B(val character: String, val nemesis: String)
|
||||
|
||||
data class C(val rowA: A, val rowB: B)
|
||||
|
||||
fun hashJoin(tableA: List<A>, tableB: List<B>): List<C> {
|
||||
val mm = tableB.groupBy { it.character }
|
||||
val tableC = mutableListOf<C>()
|
||||
for (a in tableA) {
|
||||
val value = mm[a.name] ?: continue
|
||||
for (b in value) tableC.add(C(a, b))
|
||||
}
|
||||
return tableC.toList()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val tableA = listOf(
|
||||
A(27, "Jonah"),
|
||||
A(18, "Alan"),
|
||||
A(28, "Glory"),
|
||||
A(18, "Popeye"),
|
||||
A(28, "Alan")
|
||||
)
|
||||
val tableB = listOf(
|
||||
B("Jonah", "Whales"),
|
||||
B("Jonah", "Spiders"),
|
||||
B("Alan", "Ghosts"),
|
||||
B("Alan", "Zombies"),
|
||||
B("Glory", "Buffy")
|
||||
)
|
||||
val tableC = hashJoin(tableA, tableB)
|
||||
println("A.Age A.Name B.Character B.Nemesis")
|
||||
println("----- ------ ----------- ---------")
|
||||
for (c in tableC) {
|
||||
print("${c.rowA.age} ${c.rowA.name.padEnd(6)} ")
|
||||
println("${c.rowB.character.padEnd(6)} ${c.rowB.nemesis}")
|
||||
}
|
||||
}
|
||||
34
Task/Hash-join/Phix/hash-join.phix
Normal file
34
Task/Hash-join/Phix/hash-join.phix
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
constant A = {{27,"Jonah"},
|
||||
{18,"Alan"},
|
||||
{28,"Glory"},
|
||||
{18,"Popeye"},
|
||||
{28,"Alan"}},
|
||||
B = {{"Jonah","Whales"},
|
||||
{"Jonah","Spiders"},
|
||||
{"Alan", "Ghosts"},
|
||||
{"Alan", "Zombies"},
|
||||
{"Glory","Buffy"}},
|
||||
jA = 2,
|
||||
jB = 1,
|
||||
MB = new_dict()
|
||||
sequence C = {}
|
||||
for i=1 to length(B) do
|
||||
object key = B[i][jB]
|
||||
object data = getd(key,MB)
|
||||
if data=0 then
|
||||
data = {B[i]}
|
||||
else
|
||||
data = append(data,B[i])
|
||||
end if
|
||||
putd(key,data,MB)
|
||||
end for
|
||||
for i=1 to length(A) do
|
||||
object data = getd(A[i][jA],MB)
|
||||
if sequence(data) then
|
||||
for j=1 to length(data) do
|
||||
C = append(C,{A[i],data[j]})
|
||||
end for
|
||||
end if
|
||||
end for
|
||||
destroy_dict(MB)
|
||||
pp(C,{pp_Nest,1})
|
||||
20
Task/Hash-join/PlainTeX/hash-join.tex
Normal file
20
Task/Hash-join/PlainTeX/hash-join.tex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
\newtoks\tabjoin
|
||||
\def\quark{\quark}
|
||||
\def\tabA{27:Jonah,18:Alan,28:Glory,18:Popeye,28:Alan}
|
||||
\def\tabB{Jonah:Whales,Jonah:Spiders,Alan:Ghosts,Alan:Zombies,Glory:Buffy}
|
||||
\def\mergejoin{\tabjoin{}\expandafter\mergejoini\tabA,\quark:\quark,}
|
||||
\def\mergejoini#1:#2,{%
|
||||
\ifx\quark#1\the\tabjoin
|
||||
\else
|
||||
\def\mergejoinii##1,#2:##2,{%
|
||||
\ifx\quark##2\else
|
||||
\tabjoin\expandafter{\the\tabjoin#1 : #2 : ##2\par}%
|
||||
\expandafter\mergejoinii\expandafter,%
|
||||
\fi
|
||||
}%
|
||||
\expandafter\mergejoinii\expandafter,\tabB,#2:\quark,%
|
||||
\expandafter\mergejoini
|
||||
\fi
|
||||
}
|
||||
\mergejoin
|
||||
\bye
|
||||
47
Task/Hash-join/PureBasic/hash-join.purebasic
Normal file
47
Task/Hash-join/PureBasic/hash-join.purebasic
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Structure tabA
|
||||
age.i
|
||||
name.s
|
||||
EndStructure
|
||||
|
||||
Structure tabB
|
||||
char_name.s
|
||||
nemesis.s
|
||||
EndStructure
|
||||
|
||||
NewList listA.tabA()
|
||||
NewList listB.tabB()
|
||||
|
||||
Macro SetListA(c_age, c_name)
|
||||
AddElement(listA()) : listA()\age = c_age : listA()\name = c_name
|
||||
EndMacro
|
||||
|
||||
Macro SetListB(c_char, c_nem)
|
||||
AddElement(listB()) : listB()\char_name = c_char : listB()\nemesis = c_nem
|
||||
EndMacro
|
||||
|
||||
SetListA(27, "Jonah") : SetListA(18, "Alan") : SetListA(28, "Glory")
|
||||
SetListA(18, "Popeye") : SetListA(28, "Alan")
|
||||
|
||||
SetListB("Jonah", "Whales") : SetListB("Jonah", "Spiders")
|
||||
SetListB("Alan", "Ghosts") : SetListB("Alan", "Zombies")
|
||||
SetListB("Glory", "Buffy")
|
||||
|
||||
If OpenConsole("Hash_join")
|
||||
ForEach listA()
|
||||
PrintN("Input A = "+Str(listA()\age)+~"\t"+listA()\name)
|
||||
Next
|
||||
PrintN("")
|
||||
ForEach listB()
|
||||
PrintN("Input B = "+listB()\char_name+~"\t"+listB()\nemesis)
|
||||
Next
|
||||
PrintN(~"\nOutput\nA.Age\tA.Name\tB.Char.\tB.Nemesis")
|
||||
ForEach listA()
|
||||
ForEach listB()
|
||||
If listA()\name = listB()\char_name
|
||||
PrintN(Str(listA()\age)+~"\t"+listA()\name+~"\t"+
|
||||
listB()\char_name+~"\t"+listB()\nemesis)
|
||||
EndIf
|
||||
Next
|
||||
Next
|
||||
Input()
|
||||
EndIf
|
||||
|
|
@ -12,13 +12,15 @@ fn main() {
|
|||
// hash phase
|
||||
let mut h = HashMap::new();
|
||||
for (i, a) in table_a.iter().enumerate() {
|
||||
h.entry(a.1).or_insert(vec![]).push(i);
|
||||
h.entry(a.1).or_insert_with(Vec::new).push(i);
|
||||
}
|
||||
// join phase
|
||||
for b in table_b {
|
||||
for i in h.get(b.0).unwrap_or(&vec![]) {
|
||||
let a = table_a.get(*i).unwrap();
|
||||
println!("{:?} {:?}", a, b);
|
||||
if let Some(vals) = h.get(b.0) {
|
||||
for &val in vals {
|
||||
let a = table_a.get(val).unwrap();
|
||||
println!("{:?} {:?}", a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
Task/Hash-join/Zkl/hash-join.zkl
Normal file
24
Task/Hash-join/Zkl/hash-join.zkl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
ageName:=T(27,"Jonah", 18,"Alan", 28,"Glory", 18,"Popeye", 28,"Alan");
|
||||
nameNemesis:=T("Jonah","Whales", "Jonah","Spiders", "Alan","Ghosts",
|
||||
"Alan","Zombies", "Glory","Buffy");
|
||||
|
||||
fcn addAN(age,name,d){ // keys are names, values are ( (age,...),() )
|
||||
if (r:=d.find(name)) d[name] = T(r[0].append(age),r[1]);
|
||||
else d.add(name,T(T(age),T));
|
||||
d // return d so pump will use that as result for assignment
|
||||
}
|
||||
fcn addNN(name,nemesis,d){ // values-->( (age,age...), (nemesis,...) )
|
||||
if (r:=d.find(name)){
|
||||
ages,nemesises := r;
|
||||
d[name] = T(ages,nemesises.append(nemesis));
|
||||
}
|
||||
}
|
||||
// Void.Read --> take existing i, read next one, pass both to next function
|
||||
var d=ageName.pump(Void,Void.Read,T(addAN,Dictionary()));
|
||||
nameNemesis.pump(Void,Void.Read,T(addNN,d));
|
||||
|
||||
d.println(); // the union of the two tables
|
||||
d.keys.sort().pump(Console.println,'wrap(name){ //pretty print the join
|
||||
val:=d[name]; if (not val[1])return(Void.Skip);
|
||||
String(name,":",d[name][1].concat(","));
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue