Hash join: Difference between revisions

22,994 bytes added ,  1 month ago
Added FreeBASIC
(Changed the whole SQL solution to illustrate better practices. Original solution was missing the key ingredient, the optimizer hint.)
(Added FreeBASIC)
 
(17 intermediate revisions by 11 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 428 ⟶ 512:
(27.Jonah.Whales)
(27.Jonah.Spiders)</pre>
 
=={{header|C++}}==
<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;
}
 
</lang>
{{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|C sharp}}==
;using LINQ to Objects
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 623 ⟶ 614:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 634 ⟶ 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 658 ⟶ 741:
 
(pprint (sort-by :name (hash-join s :name r :name)))
</syntaxhighlight>
</lang>
 
{{out}}
Line 673 ⟶ 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 689 ⟶ 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 704 ⟶ 787:
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.typecons;
 
auto hashJoin(size_t index1, size_t index2, T1, T2)
Line 738 ⟶ 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 750 ⟶ 833:
=={{header|Déjà Vu}}==
{{trans|Python}}
<langsyntaxhighlight lang="dejavu">hashJoin table1 index1 table2 index2:
local :h {}
# hash phase
Line 768 ⟶ 851:
 
for row in hashJoin table1 1 table2 0:
!. row</langsyntaxhighlight>
{{out}}
<pre>[ [ 27 "Jonah" ] [ "Jonah" "Whales" ] ]
Line 781 ⟶ 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 809 ⟶ 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 819 ⟶ 902:
(27 "Jonah") ("Jonah" "Spiders")
(27 "Jonah") ("Jonah" "Whales")
</syntaxhighlight>
</lang>
 
=={{header|ECL}}==
<syntaxhighlight lang="ecl">
<lang ECL>
LeftRec := RECORD
UNSIGNED1 Age;
Line 856 ⟶ 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 879 ⟶ 962:
{"Alan", "Zombies"},
{"Glory", "Buffy"}]
Hash.join(table1, 1, table2, 0) |> Enum.each(&IO.inspect &1)</langsyntaxhighlight>
 
{{out}}
Line 893 ⟶ 976:
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( hash_join ).
 
Line 911 ⟶ 994:
dict_find( error, _Key, _Value ) -> [];
dict_find( {ok, Values}, Key, Value ) -> [{X, {Key, Value}} || X <- Values].
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 923 ⟶ 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#}}==
<langsyntaxhighlight lang="fsharp">[<EntryPoint>]
let main argv =
let table1 = [27, "Jonah";
Line 947 ⟶ 1,119:
|> Seq.toList
|> printfn "%A"
0</langsyntaxhighlight>
{{out}}
<pre>[((27, "Jonah"), ("Jonah", "Whales")); ((27, "Jonah"), ("Jonah", "Spiders"));
Line 960 ⟶ 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 1,046 ⟶ 1,218:
q free:
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,057 ⟶ 1,229:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 1,087 ⟶ 1,259:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,102 ⟶ 1,274:
 
Semi-imperative style:
<syntaxhighlight lang="groovy">
<lang Groovy>
def hashJoin(table1, col1, table2, col2) {
 
Line 1,118 ⟶ 1,290:
q
}
</syntaxhighlight>
</lang>
 
More functional style:
<syntaxhighlight lang="groovy">
<lang Groovy>
def hashJoin(table1, col1, table2, col2) {
 
Line 1,130 ⟶ 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,147 ⟶ 1,319:
 
hashJoin(s, "name", r, "name").sort {it.name}.each { println it }
</syntaxhighlight>
</lang>
 
produces:
Line 1,168 ⟶ 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,196 ⟶ 1,368:
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
fst
</syntaxhighlight>
</lang>
<pre>
((3,"Glory"),("Glory","Buffy"))
Line 1,206 ⟶ 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,224 ⟶ 1,396:
("Alan", "Ghosts"), ("Alan", "Zombies"), ("Glory", "Buffy")]
fst
</syntaxhighlight>
</lang>
<pre>
((1,"Jonah"),("Jonah","Spiders"))
Line 1,237 ⟶ 1,409:
Data:
 
<langsyntaxhighlight Jlang="j">table1=: ;:;._2(0 :0)
27 Jonah
18 Alan
Line 1,251 ⟶ 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,257 ⟶ 1,429:
Implementation:
 
<langsyntaxhighlight Jlang="j">hash=: ]
dojoin=:3 :0
c1=. {.{.y
Line 1,265 ⟶ 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,284 ⟶ 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,328 ⟶ 1,500:
return result;
}
}</langsyntaxhighlight>
 
<pre>[[27, Jonah], [Jonah, Whales]]
Line 1,337 ⟶ 1,509:
[[28, Alan], [Alan, Zombies]]
[[28, Glory], [Glory, Buffy]]</pre>
 
 
=={{header|JavaScript}}==
===ES6===
 
<langsyntaxhighlight JavaScriptlang="javascript">(() => {
'use strict';
 
Line 1,397 ⟶ 1,568:
})();
</syntaxhighlight>
</lang>
 
{{Out}}
Line 1,423 ⟶ 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,457 ⟶ 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,498 ⟶ 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,512 ⟶ 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,541 ⟶ 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,554 ⟶ 1,725:
[28,"Alan","Ghosts"]
[28,"Alan","Zombies"]
[28,"Glory","Buffy"]</langsyntaxhighlight>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
For dataframes there is a builtin function join:
<langsyntaxhighlight lang="julia">using DataFrames
 
A = DataFrame(Age = [27, 18, 28, 18, 28], Name = ["Jonah", "Alan", "Glory", "Popeye", "Alan"])
Line 1,566 ⟶ 1,737:
AB = join(A, B, on = :Name)
 
@show A B AB</langsyntaxhighlight>
 
{{out}}
Line 1,597 ⟶ 1,768:
 
Following the task hint:
<langsyntaxhighlight 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], ()))
Line 1,615 ⟶ 1,786:
for r in hashjoin(table1, 2, table2, 1)
println(r)
end</langsyntaxhighlight>
 
{{out}}
Line 1,627 ⟶ 1,798:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">data class A(val age: Int, val name: String)
 
data class B(val character: String, val nemesis: String)
Line 1,665 ⟶ 1,836:
println("${c.rowB.character.padEnd(6)} ${c.rowB.nemesis}")
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,679 ⟶ 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,705 ⟶ 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,720 ⟶ 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,732 ⟶ 2,001:
(#(age 28) #(name "Alan") #(nemesis "Zombies")))
((#(age 28) #(name "Glory") #(nemesis "Buffy"))))
</syntaxhighlight>
</lang>
 
 
=={{header|M2000 Interpreter}}==
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module HashJoin {
\\ normally we define variables when we put values to names
Line 1,815 ⟶ 2,083:
}
HashJoin
</syntaxhighlight>
</lang>
{{out}}
<pre >
Line 1,833 ⟶ 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,842 ⟶ 2,110:
Partition[Flatten[Map[f,{#[[2;;]],h[#[[1]]]}&/@t2
]],Length[t1[[1]]]+Length[t2[[1]]]-1]
];</langsyntaxhighlight>
Sample run:
<pre>
Line 1,901 ⟶ 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,999 ⟶ 2,311:
DoJoinPhase(tableB,dict);
END HashJoin.
</syntaxhighlight>
</lang>
Output:
<pre>
Line 2,013 ⟶ 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 2,020 ⟶ 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 2,042 ⟶ 2,354:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use Data::Dumper qw(Dumper);
 
sub hashJoin {
Line 2,071 ⟶ 2,383:
foreach my $row (hashJoin(\@table1, 1, \@table2, 0)) {
print Dumper($row), "\n";
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,082 ⟶ 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] }
}
}
 
# Testing:
 
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 2,173 ⟶ 2,446:
 
=={{header|PHP}}==
<langsyntaxhighlight lang="php"><?php
function hashJoin($table1, $index1, $table2, $index2) {
// hash phase
Line 2,199 ⟶ 2,472:
foreach (hashJoin($table1, 1, $table2, 0) as $row)
print_r($row);
?></langsyntaxhighlight>
{{out}}
<pre>
Line 2,309 ⟶ 2,582:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de A
(27 . Jonah)
(18 . Alan)
Line 2,332 ⟶ 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,341 ⟶ 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,364 ⟶ 2,636:
}
\mergejoin
\bye</langsyntaxhighlight>
 
pdf or dvi output:
Line 2,374 ⟶ 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,422 ⟶ 2,730:
Next
Input()
EndIf</langsyntaxhighlight>
{{out}}
<pre>Input A = 27 Jonah
Line 2,447 ⟶ 2,755:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from collections import defaultdict
 
def hashJoin(table1, index1, table2, index2):
Line 2,469 ⟶ 2,777:
 
for row in hashJoin(table1, 1, table2, 0):
print(row)</langsyntaxhighlight>
{{out}}
<pre>
Line 2,482 ⟶ 2,790:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(struct A (age name))
(struct B (name nemesis))
Line 2,510 ⟶ 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,520 ⟶ 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,552 ⟶ 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,564 ⟶ 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,605 ⟶ 2,953:
next
ok
return r</langsyntaxhighlight>
{{out}}
<pre>
Line 2,621 ⟶ 2,969:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def hashJoin(table1, index1, table2, index2)
# hash phase
h = table1.group_by {|s| s[index1]}
Line 2,642 ⟶ 2,990:
["Glory", "Buffy"]]
 
hashJoin(table1, 1, table2, 0).each { |row| p row }</langsyntaxhighlight>
 
{{out}}
Line 2,656 ⟶ 3,004:
 
=={{header|Run BASIC}}==
<langsyntaxhighlight Runbasiclang="runbasic">sqliteconnect #mem, ":memory:"
 
#mem execute("CREATE TABLE t_age(age,name)")
Line 2,680 ⟶ 3,028:
nemesis$ = #row nemesis$()
print age;" ";name$;" ";nemesis$
WEND</langsyntaxhighlight>Output:
<pre>27 Jonah Spiders
27 Jonah Whales
Line 2,691 ⟶ 3,039:
 
=={{header|Rust}}==
<langsyntaxhighlight lang="rust">use std::collections::HashMap;
use std::hash::Hash;
 
Line 2,733 ⟶ 3,081:
println!("{:<3} | {:^14} | {}", age, name, nemesis);
}
}</langsyntaxhighlight>
{{out}}
<pre>Age | Character Name | Nemesis
Line 2,746 ⟶ 3,094:
 
=={{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,764 ⟶ 3,112:
List("Glory", "Buffy"))
 
println(join(table1, table2) mkString "\n")</langsyntaxhighlight>
{{out}}
<pre>List(27, Jonah, Whales)
Line 2,776 ⟶ 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,796 ⟶ 3,144:
(print (list (list age name)
person)))
</syntaxhighlight>
</lang>
{{output}}
<pre>
Line 2,809 ⟶ 3,157:
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func hashJoin(table1, index1, table2, index2) {
var a = []
var h = Hash()
Line 2,838 ⟶ 3,186:
["Glory", "Buffy"]]
 
hashJoin(t1, 1, t2, 0).each { .say }</langsyntaxhighlight>
{{out}}
<pre>[[27, 'Jonah'], ['Jonah', 'Whales']]
Line 2,850 ⟶ 3,198:
=={{header|SQL}}==
{{works with|oracle}}
<langsyntaxhighlight lang="sql">-- setting up the test data
 
create table people (age number(3), name varchar2(30));
Line 2,868 ⟶ 3,216:
select 'Alan' , 'Zombies' from dual union all
select 'Glory', 'Buffy' from dual
;</langsyntaxhighlight>
 
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.
<langsyntaxhighlight lang="sql">select /*+ use_hash */ * from people join nemesises using(name);</langsyntaxhighlight>
 
{{out}}
Line 2,883 ⟶ 3,231:
18 Alan Zombies
28 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,924 ⟶ 3,331:
foreach row $joined {
puts $row
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,940 ⟶ 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,958 ⟶ 3,365:
^(,l-entry ,r-entry)))))
 
(format t "~s\n" [hash-join age-name second nemesis-name first])</langsyntaxhighlight>
 
{{out}}
Line 2,966 ⟶ 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,997 ⟶ 3,404:
Next
End Sub
</syntaxhighlight>
</lang>
 
{{Out}}
Line 3,012 ⟶ 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 3,067 ⟶ 3,474:
RETURN a[1]
ENDFUNC
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 3,076 ⟶ 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 3,103 ⟶ 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