Hash join: Difference between revisions

32,258 bytes added ,  1 month ago
Added FreeBASIC
No edit summary
(Added FreeBASIC)
 
(27 intermediate revisions by 18 users not shown)
Line 119:
 
<br><hr>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F hash_join(table1, table2)
DefaultDict[String, [(Int, String)]] h
L(s) table1
h[s[1]].append(s)
 
[((Int, String), (String, String))] res
L(r) table2
L(s) h[r[0]]
res [+]= (s, r)
R res
 
V table1 = [(27, ‘Jonah’),
(18, ‘Alan’),
(28, ‘Glory’),
(18, ‘Popeye’),
(28, ‘Alan’)]
V table2 = [(‘Jonah’, ‘Whales’),
(‘Jonah’, ‘Spiders’),
(‘Alan’, ‘Ghosts’),
(‘Alan’, ‘Zombies’),
(‘Glory’, ‘Buffy’)]
 
L(row) hash_join(table1, table2)
print(row)</syntaxhighlight>
 
{{out}}
<pre>
((27, Jonah), (Jonah, Whales))
((27, Jonah), (Jonah, Spiders))
((18, Alan), (Alan, Ghosts))
((28, Alan), (Alan, Ghosts))
((18, Alan), (Alan, Zombies))
((28, Alan), (Alan, Zombies))
((28, Glory), (Glory, Buffy))
</pre>
 
=={{header|AppleScript}}==
Line 126 ⟶ 165:
The vertical bars distinguish AppleScript reserved words ('''name''' and '''character''' here) from field name literal strings.
 
<langsyntaxhighlight AppleScriptlang="applescript">use framework "Foundation" -- Yosemite onwards, for record-handling functions
 
-- HASH JOIN -----------------------------------------------------------------
Line 257 ⟶ 296:
set my text item delimiters to dlm
return lstParts
end splitOn</langsyntaxhighlight>
{{Out}}
<pre>{{age:27, |name|:"Jonah", |character|:"Jonah", nemesis:"Whales"},
Line 266 ⟶ 305:
{age:28, |name|:"Alan", |character|:"Alan", nemesis:"Ghosts"},
{age:28, |name|:"Alan", |character|:"Alan", nemesis:"Zombies"}}</pre>
 
=={{header|Arturo}}==
<syntaxhighlight lang="arturo">hashJoin: function [t1, t2][
result: []
h: #[]
loop t1 's [
if not? key? h s\1 -> h\[s\1]: []
h\[s\1]: h\[s\1] ++ @[s]
]
loop t2 'r [
loop h\[r\0] 's [
'result ++ @[@[s r]]
]
]
return result
]
 
table1: [
[27 "Jonah"]
[18 "Alan"]
[28 "Glory"]
[18 "Popeye"]
[28 "Alan"]
]
 
table2: [
["Jonah" "Whales"]
["Jonah" "Spiders"]
["Alan" "Ghosts"]
["Alan" "Zombies"]
["Glory" "Buffy"]
]
 
loop hashJoin table1 table2 'row ->
print row</syntaxhighlight>
 
{{out}}
 
<pre>[27 Jonah] [Jonah Whales]
[27 Jonah] [Jonah Spiders]
[18 Alan] [Alan Ghosts]
[28 Alan] [Alan Ghosts]
[18 Alan] [Alan Zombies]
[28 Alan] [Alan Zombies]
[28 Glory] [Glory Buffy] </pre>
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f HASH_JOIN.AWK [-v debug={0|1}] TABLE_A TABLE_B
#
Line 330 ⟶ 414:
return(tmp)
}
</syntaxhighlight>
</lang>
<p>TABLE_A input:</p>
<pre>
Line 363 ⟶ 447:
=={{header|Bracmat}}==
This solution creates a hash table for the smaller relation in the function <code>join</code>. This function takes as arguments the smallest table, the biggest table and then three pieces of code: two patterns that describe each table's field order and code that generates one row of output. These pieces of code are inserted in a fixed skeleton of code using macro substitution.
<langsyntaxhighlight lang="bracmat">( (27.Jonah)
(18.Alan)
(28.Glory)
Line 419 ⟶ 503:
)
&
);</langsyntaxhighlight>
Output:
<pre> (28.Alan.Ghosts)
Line 431 ⟶ 515:
=={{header|C sharp}}==
;using LINQ to Objects
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 530 ⟶ 614:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 541 ⟶ 625:
Age: 28, Name: Alan, Nemesis: Ghosts
Age: 28, Name: Alan, Nemesis: Zombies
</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
 
using tab_t = std::vector<std::vector<std::string>>;
tab_t tab1 {
// Age Name
{"27", "Jonah"}
, {"18", "Alan"}
, {"28", "Glory"}
, {"18", "Popeye"}
, {"28", "Alan"}
};
 
tab_t tab2 {
// Character Nemesis
{"Jonah", "Whales"}
, {"Jonah", "Spiders"}
, {"Alan", "Ghosts"}
, {"Alan", "Zombies"}
, {"Glory", "Buffy"}
};
 
std::ostream& operator<<(std::ostream& o, const tab_t& t) {
for(size_t i = 0; i < t.size(); ++i) {
o << i << ":";
for(const auto& e : t[i])
o << '\t' << e;
o << std::endl;
}
return o;
}
 
tab_t Join(const tab_t& a, size_t columna, const tab_t& b, size_t columnb) {
std::unordered_multimap<std::string, size_t> hashmap;
// hash
for(size_t i = 0; i < a.size(); ++i) {
hashmap.insert(std::make_pair(a[i][columna], i));
}
// map
tab_t result;
for(size_t i = 0; i < b.size(); ++i) {
auto range = hashmap.equal_range(b[i][columnb]);
for(auto it = range.first; it != range.second; ++it) {
tab_t::value_type row;
row.insert(row.end() , a[it->second].begin() , a[it->second].end());
row.insert(row.end() , b[i].begin() , b[i].end());
result.push_back(std::move(row));
}
}
return result;
}
 
int main(int argc, char const *argv[])
{
using namespace std;
int ret = 0;
cout << "Table A: " << endl << tab1 << endl;
cout << "Table B: " << endl << tab2 << endl;
auto tab3 = Join(tab1, 1, tab2, 0);
cout << "Joined tables: " << endl << tab3 << endl;
return ret;
}
 
</syntaxhighlight>
{{out}}
<pre>Table A:
0: 27 Jonah
1: 18 Alan
2: 28 Glory
3: 18 Popeye
4: 28 Alan
 
Table B:
0: Jonah Whales
1: Jonah Spiders
2: Alan Ghosts
3: Alan Zombies
4: Glory Buffy
 
Joined tables:
0: 27 Jonah Jonah Whales
1: 27 Jonah Jonah Spiders
2: 28 Alan Alan Ghosts
3: 18 Alan Alan Ghosts
4: 28 Alan Alan Zombies
5: 18 Alan Alan Zombies
6: 28 Glory Glory Buffy
</pre>
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="clojure">
(defn hash-join [table1 col1 table2 col2]
(let [hashed (group-by col1 table1)]
Line 565 ⟶ 741:
 
(pprint (sort-by :name (hash-join s :name r :name)))
</syntaxhighlight>
</lang>
 
{{out}}
Line 580 ⟶ 756:
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(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")))
Line 596 ⟶ 772:
(let ((val (car (gethash i *hash-table*))))
(loop for (a b) in val do
(format t "{~a ~a} {~a ~a}~%" a b i r))))</langsyntaxhighlight>
 
{{out}}
Line 611 ⟶ 787:
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.typecons;
 
auto hashJoin(size_t index1, size_t index2, T1, T2)
Line 645 ⟶ 821:
foreach (const row; hashJoin!(1, 0)(table1, table2))
writefln("(%s, %5s) (%5s, %7s)", row[0][], row[1][]);
}</langsyntaxhighlight>
{{out}}
<pre>(27, Jonah) (Jonah, Whales)
Line 657 ⟶ 833:
=={{header|Déjà Vu}}==
{{trans|Python}}
<langsyntaxhighlight lang="dejavu">hashJoin table1 index1 table2 index2:
local :h {}
# hash phase
Line 675 ⟶ 851:
 
for row in hashJoin table1 1 table2 0:
!. row</langsyntaxhighlight>
{{out}}
<pre>[ [ 27 "Jonah" ] [ "Jonah" "Whales" ] ]
Line 688 ⟶ 864:
=={{header|EchoLisp}}==
Since this is a real, professional application, we build the hash tables in permanent (local) storage.
<langsyntaxhighlight lang="lisp">
(define ages '((27 "Jonah") (18 "Alan") (28 "Glory") (18 "Popeye") (28 "Alan")))
(define nemesis '(("Jonah" "Whales") ("Jonah" "Spiders") ("Alan" "Ghosts") ("Alan" "Zombies") ("Glory" "Buffy")))
Line 716 ⟶ 892:
(n (local-get-value k 'NEMESIS)))
(writeln a n))
</syntaxhighlight>
</lang>
{{out}}
<langsyntaxhighlight lang="lisp">
(28 "Alan") ("Alan" "Zombies")
(28 "Alan") ("Alan" "Ghosts")
Line 726 ⟶ 902:
(27 "Jonah") ("Jonah" "Spiders")
(27 "Jonah") ("Jonah" "Whales")
</syntaxhighlight>
</lang>
 
=={{header|ECL}}==
<syntaxhighlight lang="ecl">
<lang ECL>
LeftRec := RECORD
UNSIGNED1 Age;
Line 763 ⟶ 939:
27 Jonah Spiders
*/
</syntaxhighlight>
</lang>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="elixir">defmodule Hash do
def join(table1, index1, table2, index2) do
h = Enum.group_by(table1, fn s -> elem(s, index1) end)
Line 786 ⟶ 962:
{"Alan", "Zombies"},
{"Glory", "Buffy"}]
Hash.join(table1, 1, table2, 0) |> Enum.each(&IO.inspect &1)</langsyntaxhighlight>
 
{{out}}
Line 800 ⟶ 976:
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( hash_join ).
 
Line 818 ⟶ 994:
dict_find( error, _Key, _Value ) -> [];
dict_find( {ok, Values}, Key, Value ) -> [{X, {Key, Value}} || X <- Values].
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 830 ⟶ 1,006:
{{28,"Glory"},{"Glory","Buffy"}}]
</pre>
 
=={{header|Emacs Lisp}}==
<syntaxhighlight lang="lisp">
(defun make-multi-map (rows)
(let ((multi-map nil))
(cl-loop for row in rows do
(let* ((name (car row))
(name-list (assoc name multi-map)))
(if name-list
(nconc name-list (list row))
(progn
(add-to-list 'multi-map (list name row) 't) ) ) ) )
multi-map) )
 
(defun join-tables (table1 table2)
(let ((multi-map (make-multi-map table2))
(result-table '()))
(cl-loop for row in table1 do
(let ((multi-rc (assoc (cdr row) multi-map)))
(when multi-rc
(cl-loop for multi-line in (cdr multi-rc) do
(add-to-list 'result-table
(list (car row) (cdr row) (car multi-line) (cdr multi-line))
't)))))
result-table))
 
(let ((table1 '((27 . "Jonah")
(18 . "Alan")
(28 . "Glory")
(18 . "Popeye")
(28 . "Alan")))
(table2 '(("Jonah" . "Whales")
("Jonah" . "Spiders")
("Alan" . "Ghosts")
("Alan" . "Zombies")
("Glory" . "Buffy"))))
(message "%s" (join-tables table1 table2)) )
</syntaxhighlight>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="vbnet">Type Data1
value As Integer
key As String
End Type
 
Type Data2
key As String
value As String
End Type
 
Dim table1(5) As Data1
Dim table2(5) As Data2
 
table1(1).value = 27: table1(1).key = "Jonah"
table1(2).value = 18: table1(2).key = "Alan"
table1(3).value = 28: table1(3).key = "Glory"
table1(4).value = 18: table1(4).key = "Popeye"
table1(5).value = 28: table1(5).key = "Alan"
 
table2(1).key = "Jonah": table2(1).value = "Whales"
table2(2).key = "Jonah": table2(2).value = "Spiders"
table2(3).key = "Alan": table2(3).value = "Ghosts"
table2(4).key = "Alan": table2(4).value = "Zombies"
table2(5).key = "Glory": table2(5).value = "Buffy"
 
Print String(51, "-")
Print " Age | Name || Name | Nemesis"
Print String(51, "-")
 
For i As Integer = 1 To 5
For j As Integer = 1 To 5
If table1(i).key = table2(j).key Then
Print Using " ## | \ \ || \ \ | \ \"; table1(i).value; table1(i).key; table2(j).key; table2(j).value
End If
Next j
Next i
 
Sleep</syntaxhighlight>
{{out}}
<pre>---------------------------------------------------
Age | Name || Name | Nemesis
---------------------------------------------------
27 | Jonah || Jonah | Whales
27 | Jonah || Jonah | Spiders
18 | Alan || Alan | Ghosts
18 | Alan || Alan | Zombies
28 | Glory || Glory | Buffy
28 | Alan || Alan | Ghosts
28 | Alan || Alan | Zombies</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">[<EntryPoint>]
let main argv =
let table1 = [27, "Jonah";
18, "Alan";
28, "Glory";
18, "Popeye";
28, "Alan"]
let table2 = ["Jonah", "Whales";
"Jonah", "Spiders";
"Alan", "Ghosts";
"Alan", "Zombies";
"Glory", "Buffy"]
let hash = Seq.groupBy (fun r -> snd r) table1
table2
|> Seq.collect (fun r ->
hash
|> Seq.collect (fun kv ->
if (fst r) <> (fst kv) then []
else (Seq.map (fun x -> (x, r)) (snd kv)) |> Seq.toList)
)
|> Seq.toList
|> printfn "%A"
0</syntaxhighlight>
{{out}}
<pre>[((27, "Jonah"), ("Jonah", "Whales")); ((27, "Jonah"), ("Jonah", "Spiders"));
((18, "Alan"), ("Alan", "Ghosts")); ((28, "Alan"), ("Alan", "Ghosts"));
((18, "Alan"), ("Alan", "Zombies")); ((28, "Alan"), ("Alan", "Zombies"));
((28, "Glory"), ("Glory", "Buffy"))]</pre>
 
=={{header|Forth}}==
Line 837 ⟶ 1,132:
Needs the FMS-SI (single inheritance) library code located here:
http://soton.mpeforth.com/flag/fms/index.html
<langsyntaxhighlight lang="forth">
include FMS-SI.f
include FMS-SILib.f
Line 923 ⟶ 1,218:
q free:
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 934 ⟶ 1,229:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 964 ⟶ 1,259:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 979 ⟶ 1,274:
 
Semi-imperative style:
<syntaxhighlight lang="groovy">
<lang Groovy>
def hashJoin(table1, col1, table2, col2) {
 
Line 995 ⟶ 1,290:
q
}
</syntaxhighlight>
</lang>
 
More functional style:
<syntaxhighlight lang="groovy">
<lang Groovy>
def hashJoin(table1, col1, table2, col2) {
 
Line 1,007 ⟶ 1,302:
}.flatten()
}
</syntaxhighlight>
</lang>
 
Sample run (either version as the result is the same):
<syntaxhighlight lang="groovy">
<lang Groovy>
def s = [[age: 27, name: 'Jonah'],
[age: 18, name: 'Alan'],
Line 1,024 ⟶ 1,319:
 
hashJoin(s, "name", r, "name").sort {it.name}.each { println it }
</syntaxhighlight>
</lang>
 
produces:
Line 1,045 ⟶ 1,340:
 
Placing all relations with the same selector value in a list in the hashtable allows us to join many to one/many relations.
<langsyntaxhighlight Haskelllang="haskell">{-# LANGUAGE LambdaCase, TupleSections #-}
import qualified Data.HashTable.ST.Basic as H
import Data.Hashable
Line 1,073 ⟶ 1,368:
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
fst
</syntaxhighlight>
</lang>
<pre>
((3,"Glory"),("Glory","Buffy"))
Line 1,083 ⟶ 1,378:
 
The task require hashtables; however, a cleaner and more functional solution would be to use Data.Map (based on binary trees):
<langsyntaxhighlight Haskelllang="haskell">{-# LANGUAGE TupleSections #-}
import qualified Data.Map as M
import Data.List
Line 1,101 ⟶ 1,396:
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
fst
</syntaxhighlight>
</lang>
<pre>
((1,"Jonah"),("Jonah","Spiders"))
Line 1,114 ⟶ 1,409:
Data:
 
<langsyntaxhighlight Jlang="j">table1=: ;:;._2(0 :0)
27 Jonah
18 Alan
Line 1,128 ⟶ 1,423:
Alan Zombies
Glory Buffy
)</langsyntaxhighlight>
 
The task does not specify the hash function to use, so we'll use an identity function. But [[SHA-1]] could be used instead, with a little more work (you'd need to convert the name into the bit vector needed by the SHA-1 interface). Practically speaking, though, the only benefit of SHA-1 in this context would be to slow down the join.
Line 1,134 ⟶ 1,429:
Implementation:
 
<langsyntaxhighlight Jlang="j">hash=: ]
dojoin=:3 :0
c1=. {.{.y
Line 1,142 ⟶ 1,437:
)
 
JOIN=: ; -.&a: ,/each(hash@{."1 <@dojoin/. ]) (1 1 0&#inv@|."1 table1), 1 0 1#inv"1 table2</langsyntaxhighlight>
 
Result:
 
<langsyntaxhighlight Jlang="j"> JOIN
┌─────┬──┬───────┐
│Jonah│27│Whales │
Line 1,161 ⟶ 1,456:
├─────┼──┼───────┤
│Glory│28│Buffy │
└─────┴──┴───────┘</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|PHP}}
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import java.util.*;
 
public class HashJoin {
Line 1,205 ⟶ 1,500:
return result;
}
}</langsyntaxhighlight>
 
<pre>[[27, Jonah], [Jonah, Whales]]
Line 1,214 ⟶ 1,509:
[[28, Alan], [Alan, Zombies]]
[[28, Glory], [Glory, Buffy]]</pre>
 
 
=={{header|JavaScript}}==
===ES6===
 
<langsyntaxhighlight JavaScriptlang="javascript">(() => {
'use strict';
 
Line 1,274 ⟶ 1,568:
})();
</syntaxhighlight>
</lang>
 
{{Out}}
Line 1,300 ⟶ 1,594:
 
===hashJoin===
<langsyntaxhighlight lang="jq"># hashJoin(table1; key1; table2; key2) expects the two tables to be
# arrays, either of JSON objects, or of arrays.
 
Line 1,334 ⟶ 1,628:
reduce $hash[$key][] as $r (.; . + [ $row + $r ] )
else . end)
;</langsyntaxhighlight>
 
'''Example'''
<langsyntaxhighlight lang="jq">def table1:
[ {"age": 27, "name": "Jonah"},
{"age": 18, "name": "Alan"},
Line 1,375 ⟶ 1,669:
( hashJoin(table1; "name"; table2; "name"),
hashJoin(table1a; 1; table2a; 0)
) | pp</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="sh">$ jq -c -r -n -f HashJoin.jq
 
{"age":27,"name":"Jonah","nemesis":"Whales"}
Line 1,389 ⟶ 1,683:
[28,"Alan","Alan","Ghosts"]
[28,"Alan","Alan","Zombies"]
[28,"Glory","Glory","Buffy"]</langsyntaxhighlight>
 
===hashJoinArrays===
<langsyntaxhighlight lang="jq"># The tables should be arrays of arrays;
# index1 and index2 should be the 0-based indices of the join columns.
#
Line 1,418 ⟶ 1,712:
. + [ $r + $row[0:index2] + $row[index2+1:] ] )
else . end)
;</langsyntaxhighlight>
'''Example'''
 
In the following example, the previously defined pretty-print function (pp) and tables (table1 and table2)
are used, so their definitions are not repeated here.
<langsyntaxhighlight lang="jq">hashJoinArrays(table1; 1; table2; 0) | pp</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="sh">$ jq -c -r -n -f HashJoinArrays.jq
 
[27,"Jonah","Whales"]
Line 1,431 ⟶ 1,725:
[28,"Alan","Ghosts"]
[28,"Alan","Zombies"]
[28,"Glory","Buffy"]</langsyntaxhighlight>
 
=={{header|KotlinJulia}}==
{{works with|Julia|0.6}}
<lang scala>// version 1.1.2
For dataframes there is a builtin function join:
<syntaxhighlight lang="julia">using DataFrames
 
A = DataFrame(Age = [27, 18, 28, 18, 28], Name = ["Jonah", "Alan", "Glory", "Popeye", "Alan"])
data class A(val age: Int, val name: String)
B = DataFrame(Name = ["Jonah", "Jonah", "Alan", "Alan", "Glory"],
Nemesis = ["Whales", "Spiders", "Ghosts", "Zombies", "Buffy"])
AB = join(A, B, on = :Name)
 
@show A B AB</syntaxhighlight>
 
{{out}}
<pre>A = 5×2 DataFrames.DataFrame
│ Row │ Age │ Name │
├─────┼─────┼──────────┤
│ 1 │ 27 │ "Jonah" │
│ 2 │ 18 │ "Alan" │
│ 3 │ 28 │ "Glory" │
│ 4 │ 18 │ "Popeye" │
│ 5 │ 28 │ "Alan" │
B = 5×2 DataFrames.DataFrame
│ Row │ Name │ Nemesis │
├─────┼─────────┼───────────┤
│ 1 │ "Jonah" │ "Whales" │
│ 2 │ "Jonah" │ "Spiders" │
│ 3 │ "Alan" │ "Ghosts" │
│ 4 │ "Alan" │ "Zombies" │
│ 5 │ "Glory" │ "Buffy" │
AB = 7×3 DataFrames.DataFrame
│ Row │ Age │ Name │ Nemesis │
├─────┼─────┼─────────┼───────────┤
│ 1 │ 18 │ "Alan" │ "Ghosts" │
│ 2 │ 18 │ "Alan" │ "Zombies" │
│ 3 │ 28 │ "Alan" │ "Ghosts" │
│ 4 │ 28 │ "Alan" │ "Zombies" │
│ 5 │ 28 │ "Glory" │ "Buffy" │
│ 6 │ 27 │ "Jonah" │ "Whales" │
│ 7 │ 27 │ "Jonah" │ "Spiders" │</pre>
 
Following the task hint:
<syntaxhighlight lang="julia">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</syntaxhighlight>
 
{{out}}
<pre>Tuple{Any,String}[(27, "Jonah"), ("Jonah", "Whales")]
Tuple{Any,String}[(27, "Jonah"), ("Jonah", "Spiders")]
Tuple{Any,String}[(18, "Alan"), ("Alan", "Ghosts")]
Tuple{Any,String}[(18, "Alan"), ("Alan", "Zombies")]
Tuple{Any,String}[(28, "Glory"), ("Glory", "Buffy")]
Tuple{Any,String}[(28, "Alan"), ("Alan", "Ghosts")]
Tuple{Any,String}[(28, "Alan"), ("Alan", "Zombies")]</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">data class A(val age: Int, val name: String)
 
data class B(val character: String, val nemesis: String)
Line 1,446 ⟶ 1,808:
val tableC = mutableListOf<C>()
for (a in tableA) {
val value = mm[a.name] ?: continue
if (value == null) continue
for (b in value) tableC.add(C(a, b))
}
Line 1,475 ⟶ 1,836:
println("${c.rowB.character.padEnd(6)} ${c.rowB.nemesis}")
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,489 ⟶ 1,850:
28 Alan Alan Zombies
</pre>
=={{header|Lua}}==
===Literal===
Lua tables are implemented with hash keys, so this task is a bit anti-idiomatic for Lua. That is, if you knew in advance that this would be the primary operation on the data, then you'd likely (re-)structure the data to directly support it. But, to comply with the intent of the task, the data here is initially structured as an indexed (rather than hash-keyed) array, <i>then</i> hashed dynamically. (it's analogous to the Python solution, where a list is immediately converted to a dictionary - but could have <i>began</i> as a dictionary)
<syntaxhighlight lang="lua">local function recA(age, name) return { Age=age, Name=name } end
local tabA = { recA(27,"Jonah"), recA(18,"Alan"), recA(28,"Glory"), recA(18,"Popeye"), recA(28,"Alan") }
 
local function recB(character, nemesis) return { Character=character, Nemesis=nemesis } end
local tabB = { recB("Jonah","Whales"), recB("Jonah","Spiders"), recB("Alan","Ghosts"), recB("Alan","Zombies"), recB("Glory","Buffy") }
 
local function hashjoin(taba, cola, tabb, colb)
local hash, join = {}, {}
for _,rowa in pairs(taba) do
if (not hash[rowa[cola]]) then hash[rowa[cola]] = {} end
table.insert(hash[rowa[cola]], rowa)
end
for _,rowb in pairs(tabb) do
for _,rowa in pairs(hash[rowb[colb]]) do
join[#join+1] = { A=rowa, B=rowb }
end
end
return join
end
 
for _,row in pairs(hashjoin(tabA, "Name", tabB, "Character")) do
print(row.A.Age, row.A.Name, row.B.Character, row.B.Nemesis)
end</syntaxhighlight>
{{out}}
<pre>27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
28 Alan Alan Ghosts
18 Alan Alan Zombies
28 Alan Alan Zombies
28 Glory Glory Buffy</pre>
===Idiomatic===
Or, at least semi-idiomatic / more-idiomatic, per comments above under the "Literal" implementation. Here, a "hashlist" structure is defined to allow retrieval either by indexed-list style (the database "rows") or by hashed-array-of-lists style (the database "index"), where the hash is maintained upon insert so that a later "hashjoin" operation becomes just a "join" operation. (Note that storage/performance issues are minimal, at least at this scale, as both the keys and rows in the hash are merely references, not copies.)
<syntaxhighlight lang="lua">local hashlist = {
new = function(self,key)
return setmetatable({key=key, hash={}, list={}}, {__index=self})
end,
insert = function(self,row)
self.list[#self.list+1] = row
if not self.hash[row[self.key]] then self.hash[row[self.key]]={} end
table.insert(self.hash[row[self.key]], row)
return self
end,
join = function(self,tabb)
local result = {}
for _,rowb in pairs(tabb.list) do
if (self.hash[rowb[tabb.key]]) then
for _,rowa in pairs(self.hash[rowb[tabb.key]]) do
result[#result+1] = { A=rowa, B=rowb }
end
end
end
return result
end
}
 
local function recA(age, name) return { Age=age, Name=name } end
tabA = hashlist:new("Name")
:insert(recA(27,"Jonah"))
:insert(recA(18,"Alan"))
:insert(recA(28,"Glory"))
:insert(recA(18,"Popeye"))
:insert(recA(28,"Alan"))
 
local function recB(character, nemesis) return { Character=character, Nemesis=nemesis } end
local tabB = hashlist:new("Character")
:insert(recB("Jonah","Whales"))
:insert(recB("Jonah","Spiders"))
:insert(recB("Alan","Ghosts"))
:insert(recB("Alan","Zombies"))
:insert(recB("Glory","Buffy"))
 
for _,row in pairs(tabA:join(tabB)) do
print(row.A.Age, row.A.Name, row.B.Character, row.B.Nemesis)
end
print("or vice versa:")
for _,row in pairs(tabB:join(tabA)) do
print(row.B.Age, row.B.Name, row.A.Character, row.A.Nemesis)
end</syntaxhighlight>
{{out}}
<pre>27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
28 Alan Alan Ghosts
18 Alan Alan Zombies
28 Alan Alan Zombies
28 Glory Glory Buffy
or vice versa:
27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
18 Alan Alan Zombies
28 Glory Glory Buffy
28 Alan Alan Ghosts
28 Alan Alan Zombies</pre>
 
=={{header|LFE}}==
<langsyntaxhighlight lang="lisp">
(defun hash (column table)
(lists:foldl
Line 1,515 ⟶ 1,974:
(lc ((<- s (get-hash col-2 hashed)))
(merge r s)))))
</syntaxhighlight>
</lang>
 
Table definitions in the LFE REPL:
<langsyntaxhighlight lang="lisp">
> (set ss '((#(age 27) #(name "Jonah"))
(#(age 18) #(name "Alan"))
Line 1,530 ⟶ 1,989:
(#(nemesis "Zombies") #(name "Alan"))
(#(nemesis "Buffy") #(name "Glory"))))
</syntaxhighlight>
</lang>
 
Output in LFE REPL:
<langsyntaxhighlight lang="lisp">
> (hash-join ss 'name rs 'name)
(((#(age 27) #(name "Jonah") #(nemesis "Whales")))
Line 1,542 ⟶ 2,001:
(#(age 28) #(name "Alan") #(nemesis "Zombies")))
((#(age 28) #(name "Glory") #(nemesis "Buffy"))))
</syntaxhighlight>
</lang>
 
=={{header|M2000 Interpreter}}==
<syntaxhighlight lang="m2000 interpreter">
Module HashJoin {
\\ normally we define variables when we put values to names
\\ so we can remove these two lines
Def Name$, Nemesis$
Def Long m, mc, items_size, A
\\ Lets make a container which use keys with hash function
Inventory A
\\ A now is a pointer to an Inventory, with Len(A)=0
\\ Print Type$(A)="Inventory"
\\ empty stack. We use current stack to place data
Flush
\Input B
data "Jonah", "Whales"
data "Jonah", "Spiders"
data "Alan", "Ghosts"
data "Alan", "Zombies"
data "Glory", "Buffy"
\\ Keys are unique, This is the HASH PHASE
While not empty {
Read Name$, Nemesis$
If Exist(A, Name$) Then {
m=Eval(A) ' get a pointer to array
Stack m {Data Nemesis$}
} Else Append A, Name$:=Stack:=Nemesis$ ' a stack object with one item
}
\\ Input A, this is the Long Table
data 27, "Jonah"
data 18, "Alan"
data 28, "Glory"
data 18, "Popeye"
data 28, "Alan"
\\ This is the JOIN PHASE
items_size=stack.size/2
\\ using items_size we can append data (using data) to stack
\\ $(0) is the default handler for columns.
\\ Letters justify to left, numbers to right.
\\ Letters can use more columns, and maybe wrap to more lines.
Print $(0), "Output during join"
Print "A.Age", "A.Name","B.Character", "B.Nemesis"
While items_size>0 {
Read Age, Name$
If exist(A, Name$) Then {
m=Eval(A) ' extract a pointer, this is for a stack object
mc=Each(m) ' make an iterator
While mc {
\\ we use $(1) for left justify numbers too
\\ normal StackItem$(stackobject) return top only
\\ we have to use StackItem$(stackobject, 3) to get 3rd
\\ or StackItem(stackobject, 3) if it is numeric.
\\ but here mc is iterator, and place the cursor value to it
Print $(1), Age, Name$,Name$, StackItem$(mc)
\\ so now we place at the end of current stack the same output
Data Age, Name$,Name$, StackItem$(mc)
}
}
items_size--
}
\\ split rem line after : to use second way
rem : goto secondway
Print $(0), "Output after join"
Print "A.Age", "A.Name","B.Character", "B.Nemesis"
While not Empty {
Print $(1), Number, Letter$, Letter$, Letter$
}
Exit
secondway:
Print $(0), "Output after join using format$()"
Print Format$("{0:5} {1:10} {2:10} {3:20}","A.Age", "A.Name","B.Character", "B.Nemesis")
While not Empty {
Print format$("{0::5} {1:10} {2:10} {3:20}", Number, Letter$, Letter$, Letter$)
}
}
HashJoin
</syntaxhighlight>
{{out}}
<pre >
27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
18 Alan Alan Zombies
28 Glory Glory Buffy
28 Alan Alan Ghosts
28 Alan Alan Zombies
 
</pre >
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
Line 1,549 ⟶ 2,101:
 
Updated version is now able to join wider tables by giving the index. The smaller table is hashed but this might result in different column ordering. Uses Associations introduced in Mathematica Version 10
<langsyntaxhighlight lang="mathematica">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];
Line 1,558 ⟶ 2,110:
Partition[Flatten[Map[f,{#[[2;;]],h[#[[1]]]}&/@t2
]],Length[t1[[1]]]+Length[t2[[1]]]-1]
];</langsyntaxhighlight>
Sample run:
<pre>
Line 1,617 ⟶ 2,169:
28 4 Glory 35 Buffy
</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import strformat, tables
 
type
Data1 = tuple[value: int; key: string]
Data2 = tuple[key: string; value: string]
 
proc `$`(d: Data1 | Data2): string = &"({d[0]}, {d[1]})"
 
iterator hashJoin(table1: openArray[Data1]; table2: openArray[Data2]): tuple[a: Data1; b: Data2] =
# Hash phase.
var h: Table[string, seq[Data1]]
for s in table1:
h.mgetOrPut(s.key, @[]).add(s)
# Join phase.
for r in table2:
for s in h[r.key]:
yield (s, r)
 
 
let table1 = [(27, "Jonah"),
(18, "Alan"),
(28, "Glory"),
(18, "Popeye"),
(28, "Alan")]
 
let table2 = [("Jonah", "Whales"),
("Jonah", "Spiders"),
("Alan", "Ghosts"),
("Alan", "Zombies"),
("Glory", "Buffy")]
 
for row in hashJoin(table1, table2):
echo row.a, " ", row.b</syntaxhighlight>
 
{{out}}
<pre>(27, Jonah) (Jonah, Whales)
(27, Jonah) (Jonah, Spiders)
(18, Alan) (Alan, Ghosts)
(28, Alan) (Alan, Ghosts)
(18, Alan) (Alan, Zombies)
(28, Alan) (Alan, Zombies)
(28, Glory) (Glory, Buffy)</pre>
 
=={{header|Oberon-2}}==
Works with oo2c version 2
<langsyntaxhighlight lang="oberon2">
MODULE HashJoin;
IMPORT
Line 1,715 ⟶ 2,311:
DoJoinPhase(tableB,dict);
END HashJoin.
</syntaxhighlight>
</lang>
Output:
<pre>
Line 1,729 ⟶ 2,325:
=={{header|OCaml}}==
This exploits the fact that Hashtbl implements a hash table that can store multiple values for a key, for an especially simple solution:
<langsyntaxhighlight lang="ocaml">let hash_join table1 f1 table2 f2 =
let h = Hashtbl.create 42 in
(* hash phase *)
Line 1,736 ⟶ 2,332:
(* join phase *)
List.concat (List.map (fun r ->
List.map (fun s -> s, r) (Hashtbl.find_all h (f2 r))) table2)</langsyntaxhighlight>
Sample run:
<pre>
Line 1,758 ⟶ 2,354:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use Data::Dumper qw(Dumper);
 
sub hashJoin {
Line 1,787 ⟶ 2,383:
foreach my $row (hashJoin(\@table1, 1, \@table2, 0)) {
print Dumper($row), "\n";
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,798 ⟶ 2,394:
$VAR1 = [[28,'Glory'],['Glory','Buffy']];
</pre>
 
=={{header|Perl 6}}==
 
The <tt>.classify</tt> method returns a multimap represented as a <tt>Hash</tt> whose values are <tt>Array</tt>s.
 
{{works with|Rakudo|2016.07}}
<lang perl6>sub hash-join(@a, &a, @b, &b) {
my %hash := @b.classify(&b);
@a.map: -> $a {
|(%hash{a $a} // next).map: -> $b { [$a, $b] }
}
}</lang>
 
Testing:
 
<lang perl6>my @A =
[27, "Jonah"],
[18, "Alan"],
[28, "Glory"],
[18, "Popeye"],
[28, "Alan"],
;
 
my @B =
["Jonah", "Whales"],
["Jonah", "Spiders"],
["Alan", "Ghosts"],
["Alan", "Zombies"],
["Glory", "Buffy"],
;
 
.say for hash-join @A, *[1], @B, *[0];</lang>
 
{{out}}
<pre>[[27 Jonah] [Jonah Whales]]
[[27 Jonah] [Jonah Spiders]]
[[18 Alan] [Alan Ghosts]]
[[18 Alan] [Alan Zombies]]
[[28 Glory] [Glory Buffy]]
[[28 Alan] [Alan Ghosts]]
[[28 Alan] [Alan Zombies]]</pre>
 
=={{header|Phix}}==
Phix dictionary keys must be unique, but storing/extending a sequence is no trouble, and in fact simplifies the scan phase.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>constant A = {{27,"Jonah"},
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
{18,"Alan"},
<span style="color: #008080;">constant</span> <span style="color: #000000;">A</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">27</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Jonah"</span><span style="color: #0000FF;">},</span>
{28,"Glory"},
<span style="color: #0000FF;">{</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Alan"</span><span style="color: #0000FF;">},</span>
{18,"Popeye"},
<span style="color: #0000FF;">{</span><span style="color: #000000;">28</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Glory"</span><span style="color: #0000FF;">},</span>
{28,"Alan"}},
<span style="color: #0000FF;">{</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Popeye"</span><span style="color: #0000FF;">},</span>
B = {{"Jonah","Whales"},
<span style="color: #0000FF;">{</span><span style="color: #000000;">28</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Alan"</span><span style="color: #0000FF;">}},</span>
{"Jonah","Spiders"},
<span style="color: #000000;">B</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"Jonah"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Whales"</span><span style="color: #0000FF;">},</span>
{"Alan", "Ghosts"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Jonah"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Spiders"</span><span style="color: #0000FF;">},</span>
{"Alan", "Zombies"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Alan"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Ghosts"</span><span style="color: #0000FF;">},</span>
{"Glory","Buffy"}},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Alan"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Zombies"</span><span style="color: #0000FF;">},</span>
jA = 2,
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Glory"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Buffy"</span><span style="color: #0000FF;">}},</span>
jB = 1,
<span style="color: #000000;">jA</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span>
MB = new_dict()
<span style="color: #000000;">jB</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
sequence C = {}
<span style="color: #000000;">MB</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">()</span>
for i=1 to length(B) do
<span style="color: #004080;">sequence</span> <span style="color: #000000;">C</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
object key = B[i][jB]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">B</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
object data = getd(key,MB)
<span style="color: #004080;">object</span> <span style="color: #000000;">key</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">B</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">jB</span><span style="color: #0000FF;">]</span>
if data=0 then
<span style="color: #004080;">object</span> <span style="color: #000000;">data</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #000000;">MB</span><span style="color: #0000FF;">)</span>
data = {B[i]}
<span style="color: #008080;">if</span> <span style="color: #000000;">data</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
else
<span style="color: #000000;">data</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">B</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]}</span>
data = append(data,B[i])
<span style="color: #008080;">else</span>
end if
<span style="color: #000000;">data</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">data</span><span style="color: #0000FF;">,</span><span style="color: #000000;">B</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
putd(key,data,MB)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #7060A8;">putd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #000000;">data</span><span style="color: #0000FF;">,</span><span style="color: #000000;">MB</span><span style="color: #0000FF;">)</span>
for i=1 to length(A) do
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
object data = getd(A[i][jA],MB)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">A</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if sequence(data) then
<span style="color: #004080;">object</span> <span style="color: #000000;">data</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">A</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">jA</span><span style="color: #0000FF;">],</span><span style="color: #000000;">MB</span><span style="color: #0000FF;">)</span>
for j=1 to length(data) do
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">data</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
C = append(C,{A[i],data[j]})
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">data</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">C</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">data</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]})</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
destroy_dict(MB)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
pp(C,{pp_Nest,1})</lang>
<span style="color: #7060A8;">destroy_dict</span><span style="color: #0000FF;">(</span><span style="color: #000000;">MB</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,889 ⟶ 2,446:
 
=={{header|PHP}}==
<langsyntaxhighlight lang="php"><?php
function hashJoin($table1, $index1, $table2, $index2) {
// hash phase
Line 1,915 ⟶ 2,472:
foreach (hashJoin($table1, 1, $table2, 0) as $row)
print_r($row);
?></langsyntaxhighlight>
{{out}}
<pre>
Line 2,025 ⟶ 2,582:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de A
(27 . Jonah)
(18 . Alan)
Line 2,048 ⟶ 2,605:
(let? Y (car (idx 'M (cons (char (hash (cdr X))) (cdr X))))
(for Z (caar Y)
(println (car X) (cdr X) (cdr Y) Z) ) ) )</langsyntaxhighlight>
Output:
<pre>27 Jonah Jonah Spiders
Line 2,057 ⟶ 2,614:
28 Alan Alan Zombies
28 Alan Alan Ghosts</pre>
 
 
=={{header|plainTeX}}==
Works with any TeX engine.
<langsyntaxhighlight lang="tex">\newtoks\tabjoin
\def\quark{\quark}
\def\tabA{27:Jonah,18:Alan,28:Glory,18:Popeye,28:Alan}
Line 2,080 ⟶ 2,636:
}
\mergejoin
\bye</langsyntaxhighlight>
 
pdf or dvi output:
Line 2,090 ⟶ 2,646:
28 : Alan : Ghosts
28 : Alan : Zombies</pre>
 
=={{header|Prolog}}==
<syntaxhighlight lang="prolog">% Name/Age
person_age('Jonah', 27).
person_age('Alan', 18).
person_age('Glory', 28).
person_age('Popeye', 18).
person_age('Alan', 28).
 
% Character/Nemesis
character_nemisis('Jonah', 'Whales').
character_nemisis('Jonah', 'Spiders').
character_nemisis('Alan', 'Ghosts').
character_nemisis('Alan', 'Zombies').
character_nemisis('Glory', 'Buffy').
 
join_and_print :-
format('Age\tName\tCharacter\tNemisis\n\n'),
forall(
(person_age(Person, Age), character_nemisis(Person, Nemesis)),
format('~w\t~w\t~w\t\t~w\n', [Age, Person, Person, Nemesis])
).</syntaxhighlight>
{{out}}
<pre>
?- join_and_print.
Age Name Character Nemisis
 
27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
18 Alan Alan Zombies
28 Glory Glory Buffy
28 Alan Alan Ghosts
28 Alan Alan Zombies
true.
</pre>
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Structure tabA
age.i
name.s
Line 2,138 ⟶ 2,730:
Next
Input()
EndIf</langsyntaxhighlight>
{{out}}
<pre>Input A = 27 Jonah
Line 2,163 ⟶ 2,755:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from collections import defaultdict
 
def hashJoin(table1, index1, table2, index2):
Line 2,185 ⟶ 2,777:
 
for row in hashJoin(table1, 1, table2, 0):
print(row)</langsyntaxhighlight>
{{out}}
<pre>
Line 2,198 ⟶ 2,790:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(struct A (age name))
(struct B (name nemesis))
Line 2,226 ⟶ 2,818:
(key (in-value (B-name b)))
(age (in-list (hash-ref name->ages# key))))
(AB key age (B-nemesis b)))</langsyntaxhighlight>
 
{{out}}
Line 2,236 ⟶ 2,828:
#(struct:AB "Alan" 28 "Zombies")
#(struct:AB "Glory" 28 "Buffy"))</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
 
The <tt>.classify</tt> method returns a multimap represented as a <tt>Hash</tt> whose values are <tt>Array</tt>s.
 
<syntaxhighlight lang="raku" line>sub hash-join(@a, &a, @b, &b) {
my %hash := @b.classify(&b);
@a.map: -> $a {
|(%hash{$a.&a} // next).map: -> $b { [$a, $b] }
}
}
 
my @A =
[27, "Jonah"],
[18, "Alan"],
[28, "Glory"],
[18, "Popeye"],
[28, "Alan"],
;
 
my @B =
["Jonah", "Whales"],
["Jonah", "Spiders"],
["Alan", "Ghosts"],
["Alan", "Zombies"],
["Glory", "Buffy"],
;
 
.say for hash-join @A, *[1], @B, *[0];</syntaxhighlight>
 
{{out}}
<pre>[[27 Jonah] [Jonah Whales]]
[[27 Jonah] [Jonah Spiders]]
[[18 Alan] [Alan Ghosts]]
[[18 Alan] [Alan Zombies]]
[[28 Glory] [Glory Buffy]]
[[28 Alan] [Alan Ghosts]]
[[28 Alan] [Alan Zombies]]</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program demonstrates the classic hash join algorithm for two relations. */
S. = ; R. =
S.1 = 27 'Jonah' ; R.1 = "Jonah Whales"
Line 2,268 ⟶ 2,900:
if nems=='' then iterate /*No nemesis? Skip. */
say pad right(age,3) pad center(name,20) pad center(nems,30) /*display an "S". */
end /*n*/ /*stick a fork in it, we're all done. */</langsyntaxhighlight>
'''output''' &nbsp; when using the in-code relations (data):
<pre>
Line 2,280 ⟶ 2,912:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">Table1 = [[27, "Jonah"], [18, "Alan"], [28, "Glory"], [18, "Popeye"], [28, "Alan"]]
Table2 = [["Jonah", "Whales"], ["Jonah", "Spiders"], ["Alan", "Ghosts"], ["Alan", "Zombies"], ["Glory", "Buffy"]]
hTable = []
Line 2,321 ⟶ 2,953:
next
ok
return r</langsyntaxhighlight>
{{out}}
<pre>
Line 2,337 ⟶ 2,969:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def hashJoin(table1, index1, table2, index2)
# hash phase
h = table1.group_by {|s| s[index1]}
Line 2,358 ⟶ 2,990:
["Glory", "Buffy"]]
 
hashJoin(table1, 1, table2, 0).each { |row| p row }</langsyntaxhighlight>
 
{{out}}
Line 2,372 ⟶ 3,004:
 
=={{header|Run BASIC}}==
<langsyntaxhighlight Runbasiclang="runbasic">sqliteconnect #mem, ":memory:"
 
#mem execute("CREATE TABLE t_age(age,name)")
Line 2,396 ⟶ 3,028:
nemesis$ = #row nemesis$()
print age;" ";name$;" ";nemesis$
WEND</langsyntaxhighlight>Output:
<pre>27 Jonah Spiders
27 Jonah Whales
Line 2,407 ⟶ 3,039:
 
=={{header|Rust}}==
<langsyntaxhighlight lang="rust">use std::collections::HashMap;
use std::hash::Hash;
 
// If you know one of the tables is smaller, it is best to make it the second parameter.
fn hash_join<A, B, K>(first: &[(K, A)], second: &[(K, B)]) -> Vec<(A, K, B)>
where
K: Hash + Eq + Copy,
A: Copy,
B: Copy,
{
let mut hash_map = HashMap::new();
 
fn main() {
let table_a = vec![
(27, "Jonah"), (18, "Alan"), (28, "Glory"),
(18, "Popeye"), (28, "Alan")
];
let table_b = vec![
("Jonah", "Whales"), ("Jonah", "Spiders"), ("Alan", "Ghosts"),
("Alan", "Zombies"), ("Glory", "Buffy")
];
// hash phase
for &(key, val_a) in second {
let mut h = HashMap::new();
// collect all values by their keys, appending new ones to each existing entry
for (i, a) in table_a.iter().enumerate() {
hhash_map.entry(a.1key).or_insert_with(Vec::new).push(ival_a);
}
 
let mut result = Vec::new();
// join phase
for b&(key, val_b) in table_bfirst {
if let Some(vals) = hhash_map.get(b.0&key) {
forlet &valtuples in= vals.iter().map(|&val_a| (val_b, key, {val_a));
let a = table_aresult.get(val).unwrapextend(tuples);
println!("{:?} {:?}", a, b);
}
}
}
 
result
}
 
</lang>
fn main() {
let table1 = [("Jonah", 27), ("Alan", 18), ("Glory", 28), ("Popeye", 18), ("Alan", 28)];
let table2 = [
("Jonah", "Whales"), ("Jonah", "Spiders"), ("Alan", "Ghosts"),
("Alan", "Zombies"), ("Glory", "Buffy")
];
let result = hash_join(&table1, &table2);
println!("Age | Character Name | Nemesis");
println!("----|----------------|--------");
for (age, name, nemesis) in result {
println!("{:<3} | {:^14} | {}", age, name, nemesis);
}
}</syntaxhighlight>
{{out}}
<pre>Age | Character Name | Nemesis
<pre>
----|----------------|--------
(27, "Jonah") ("Jonah", "Whales")
(27, "Jonah") ("| Jonah", "Spiders") | Whales
27 | Jonah | Spiders
(18, "Alan") ("Alan", "Ghosts")
(28,18 | "Alan") ("Alan", " | Ghosts")
(18, "Alan") ("| Alan", " | Zombies")
28 | Glory | Buffy
(28, "Alan") ("Alan", "Zombies")
28 | Alan | Ghosts
(28, "Glory") ("Glory", "Buffy")
28 | Alan | Zombies</pre>
</pre>
 
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">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))
Line 2,464 ⟶ 3,112:
List("Glory", "Buffy"))
 
println(join(table1, table2) mkString "\n")</langsyntaxhighlight>
{{out}}
<pre>List(27, Jonah, Whales)
Line 2,476 ⟶ 3,124:
=={{header|Scheme}}==
{{works with|Gauche Scheme}}
<langsyntaxhighlight Schemelang="scheme">(use srfi-42)
 
(define ages '((27 Jonah) (18 Alan) (28 Glory) (18 Popeye) (28 Alan)))
Line 2,496 ⟶ 3,144:
(print (list (list age name)
person)))
</syntaxhighlight>
</lang>
{{output}}
<pre>
Line 2,509 ⟶ 3,157:
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func hashJoin(table1, index1, table2, index2) {
var a = []
var h = Hash()
Line 2,538 ⟶ 3,186:
["Glory", "Buffy"]]
 
hashJoin(t1, 1, t2, 0).each { .say }</langsyntaxhighlight>
{{out}}
<pre>[[27, 'Jonah'], ['Jonah', 'Whales']]
Line 2,549 ⟶ 3,197:
 
=={{header|SQL}}==
{{works with|oracle}}
Setting up the data is a bit verbose:
<syntaxhighlight lang="sql">-- setting up the test data
<lang sql>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 nemesisespeople (nameage varcharnumber(163), nemesisname varcharvarchar2(1630));
insert into nemesisespeople (nameage, nemesis) values ('Jonah', 'Whales'name);
select 27, 'Jonah' from dual union all
insert into nemesises (name, nemesis) values ('Jonah', 'Spiders');
select 18, 'Alan' from dual union all
insert into nemesises (name, nemesis) values ('Alan', 'Ghosts');
select 28, 'Glory' from dual union all
insert into nemesises (name, nemesis) values ('Alan', 'Zombies');
select 18, 'Popeye' from dual union all
insert into nemesises (name, nemesis) values ('Glory', 'Buffy');</lang>
select 28, 'Alan' from dual
;
 
create table nemesises (name varchar2(30), nemesis varchar2(30));
Doing the join is concise. But we don't actually have control over how the join is implemented, so this might not actually be a hash join...
<langinsert sql>select * from people p joininto nemesises n on p.(name, =nemesis) n.name</lang>
select 'Jonah', 'Whales' from dual union all
select 'Jonah', 'Spiders' from dual union all
select 'Alan' , 'Ghosts' from dual union all
select 'Alan' , 'Zombies' from dual union all
select 'Glory', 'Buffy' from dual
;</syntaxhighlight>
 
Doing the join is trivial. Normally we would let the optimizer select the join method. However, to force a hash join, we can use an optimizer hint, USE_HASH.
<syntaxhighlight lang="sql">select /*+ use_hash */ * from people join nemesises using(name);</syntaxhighlight>
 
{{out}}
<pre> AGE NAME NAME NEMESIS
---------- ---------------- ---------------- ----------------
27 Jonah Jonah Whales
27 Jonah Jonah Spiders
28 Alan Alan Ghosts
18 Alan Alan Ghosts
28 Alan Alan Zombies
18 Alan Alan Zombies
28 Glory Glory Buffy</pre>
 
=={{header|Swift}}==
 
{{trans|Rust}}
 
<syntaxhighlight lang="swift">func hashJoin<A, B, K: Hashable>(_ first: [(K, A)], _ second: [(K, B)]) -> [(A, K, B)] {
var map = [K: [B]]()
 
for (key, val) in second {
map[key, default: []].append(val)
}
 
var res = [(A, K, B)]()
 
for (key, val) in first {
guard let vals = map[key] else {
continue
}
 
res += vals.map({ (val, key, $0) })
}
 
return res
}
 
let t1 = [
("Jonah", 27),
("Alan", 18),
("Glory", 28),
("Popeye", 18),
("Alan", 28)
]
 
let t2 = [
("Jonah", "Whales"),
("Jonah", "Spiders"),
("Alan", "Ghosts"),
("Alan", "Zombies"),
("Glory", "Buffy")
]
 
print("Age | Character Name | Nemesis")
print("----|----------------|--------")
 
for (age, name, nemesis) in hashJoin(t1, t2) {
print("\(age) | \(name) | \(nemesis)")
}</syntaxhighlight>
 
{{out}}
 
<pre>Age | Character Name | Nemesis
----|----------------|--------
27 | Jonah | Whales
27 | Jonah | Spiders
18 | Alan | Ghosts
18 | Alan | Zombies
28 | Glory | Buffy
28 | Alan | Ghosts
28 | Alan | Zombies</pre>
 
=={{header|Tcl}}==
Tcl uses hash tables to implement both its associative arrays and its dictionaries.
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
# Only for lmap, which can be replaced with foreach
 
Line 2,618 ⟶ 3,331:
foreach row $joined {
puts $row
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,634 ⟶ 3,347:
Generic hash join. Arguments <code>left-key</code> and <code>right-key</code> are functions applied to the elements of the <code>left</code> and <code>right</code> sequences to retrieve the join key.
 
<langsyntaxhighlight lang="txrlisp">(defvar age-name '((27 Jonah)
(18 Alan)
(28 Glory)
Line 2,652 ⟶ 3,365:
^(,l-entry ,r-entry)))))
 
(format t "~s\n" [hash-join age-name second nemesis-name first])</langsyntaxhighlight>
 
{{out}}
Line 2,660 ⟶ 3,373:
 
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
<lang vb>
Dim t_age(4,1)
t_age(0,0) = 27 : t_age(0,1) = "Jonah"
Line 2,691 ⟶ 3,404:
Next
End Sub
</syntaxhighlight>
</lang>
 
{{Out}}
Line 2,706 ⟶ 3,419:
=={{header|Visual FoxPro}}==
Hashing using the common key (name) gives ambiguous results as the name column is not unique in either table (a unique key could be formed by using the age and name columns) . This implementation forces a unique key on the people table.
<langsyntaxhighlight lang="vfp">
LOCAL i As Integer, n As Integer
CLOSE DATABASES ALL
Line 2,761 ⟶ 3,474:
RETURN a[1]
ENDFUNC
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,770 ⟶ 3,483:
18 Alan Zombies
28 Glory Buffy
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
 
class A {
construct new(age, name) {
_age = age
_name = name
}
 
age { _age }
name { _name }
}
 
class B {
construct new(character, nemesis) {
_character = character
_nemesis = nemesis
}
 
character { _character }
nemesis { _nemesis }
}
 
var tableA = [
A.new(27, "Jonah"), A.new(18, "Alan"), A.new(28, "Glory"),
A.new(18, "Popeye"), A.new(28, "Alan")
]
var tableB = [
B.new("Jonah", "Whales"), B.new("Jonah", "Spiders"), B.new("Alan", "Ghosts"),
B.new("Alan", "Zombies"), B.new("Glory", "Buffy")
]
var h = {}
var i = 0
for (a in tableA) {
var n = h[a.name]
if (n) {
n.add(i)
} else {
h[a.name] = [i]
}
i = i + 1
}
 
System.print("Age Name Character Nemesis")
System.print("--- ----- --------- -------")
for (b in tableB) {
var c = h[b.character]
if (c) {
for (i in c) {
var t = tableA[i]
Fmt.print("$3d $-5s $-9s $s", t.age, t.name, b.character, b.nemesis)
}
}
}</syntaxhighlight>
 
{{out}}
<pre>
Age Name Character Nemesis
--- ----- --------- -------
27 Jonah Jonah Whales
27 Jonah Jonah Spiders
18 Alan Alan Ghosts
28 Alan Alan Ghosts
18 Alan Alan Zombies
28 Alan Alan Zombies
28 Glory Glory Buffy
</pre>
 
=={{header|zkl}}==
Join two tables by hashing on the common key (name). The resulting join is the intersection of the two tables.
<langsyntaxhighlight lang="zkl">ageName:=T(27,"Jonah", 18,"Alan", 28,"Glory", 18,"Popeye", 28,"Alan");
nameNemesis:=T("Jonah","Whales", "Jonah","Spiders", "Alan","Ghosts",
"Alan","Zombies", "Glory","Buffy");
Line 2,797 ⟶ 3,579:
val:=d[name]; if (not val[1])return(Void.Skip);
String(name,":",d[name][1].concat(","));
})</langsyntaxhighlight>
zkl Dictionaries only have one key
<pre>
2,123

edits