2018-10-10 18:03:03 -04:00
---
title: Hash join
id: 5956795bc9e2c415eb244de1
challengeType: 5
2019-08-28 16:26:13 +03:00
forumTopicId: 302284
2018-10-10 18:03:03 -04:00
localeTitle: Присоединиться
---
## Description
2019-08-28 16:26:13 +03:00
< section id = 'description' >
< p > < a href = "https://en.wikipedia.org/wiki/Join_(SQL) #Inner_join " title = "wp: Join_ (SQL) #Inner_join " > Внутреннее соединение</ a > - это операция, которая объединяет две таблицы данных в одну таблицу на основе совпадающих значений столбцов. Простейшим способом реализации этой операции является алгоритм < a href = "https://en.wikipedia.org/wiki/Nested loop join" title = "wp: Соединение вложенного цикла" > объединения вложенных циклов</ a > , но более масштабируемой альтернативой является алгоритм < a href = "https://en.wikipedia.org/wiki/hash join" title = "wp: hash join" > хеш-соединения</ a > . </ p >< p > Внедрите алгоритм «хеш-соединения» и продемонстрируйте, что он проходит тестовый сценарий, указанный ниже. </ p >< p > Вы должны представлять таблицы как структуры данных, которые кажутся естественными на вашем языке программирования. </ p >< p > Алгоритм «хеш-соединения» состоит из двух шагов: </ p > Хэш-фаза. Создайте < a href = "https://en.wikipedia.org/wiki/Multimap" title = "wp: Multimap" > мультимап</ a > из одной из двух таблиц, сопоставляя их с о всеми значениями столбца объединения с о всеми строками, которые е г о содержат. Мультимап должен поддерживать хэш-ориентированный поиск, который масштабируется лучше, чем простой линейный поиск, потому что в этом весь смысл этого алгоритма. В идеале мы должны создать мультимап для меньшей таблицы, таким образом минимизируя время е г о создания и размер памяти. Фаза присоединения. Сканируйте другую таблицу и найдите соответствующие строки, просмотрев созданный ранее мультимап. < p > В псевдокоде алгоритм может быть выражен следующим образом: </ p >< pre > пусть A = первая входная таблица (или, в идеале, большая)
2018-10-10 18:03:03 -04:00
пусть B = вторая входная таблица (или, в идеале, меньшая)
пусть j < sub > A< / sub > = идентификатор столбца соединения таблицы A
пусть j < sub > B< / sub > = идентификатор столбца соединения таблицы B
пусть M < sub > B< / sub > = мультимап для отображения из отдельных значений в несколько строк таблицы B (начинается пустым)
пусть C = выходная таблица (начинается пустая)
для каждой строки b в таблице B:
место b в multimap M < sub > B< / sub > под клавишей b (j < sub > B< / sub > )
для каждой строки a в таблице A:
для каждой строки b в мультимадре M < sub > B< / sub > под ключом a (j < sub > A< / sub > ):
пусть c = конкатенация строки a и строки b
поместите строку c в таблицу C < p > < / p >
2019-08-28 16:26:13 +03:00
< / pre > Прецедент < p > вход < / p > < table > < tbody > < tr > < td style = "padding: 4px; margin: 5px;" > < table style = "border:none; border-collapse:collapse;" > < tbody > < tr > < td style = "border:none" > < i > A =< / i > < / td > < td style = "border:none" > < table > < tbody > < tr > < th style = "padding: 4px; margin: 5px;" > Возраст < / th > < th style = "padding: 4px; margin: 5px;" > имя < / th > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 27 < / td > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 18 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 28 < / td > < td style = "padding: 4px; margin: 5px;" > слава < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 18 < / td > < td style = "padding: 4px; margin: 5px;" > Popeye < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 28 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < / tr > < / tbody > < / table > < / td > < td style = "border:none; padding-left:1.5em;" rowspan = "2" > < / td > < td style = "border:none" > < i > B =< / i > < / td > < td style = "border:none" > < table > < tbody > < tr > < th style = "padding: 4px; margin: 5px;" > символ < / th > < th style = "padding: 4px; margin: 5px;" > Немезида < / th > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Киты < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Пауки < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > привидения < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Zombies < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > слава < / td > < td style = "padding: 4px; margin: 5px;" > Buffy < / td > < / tr > < / tbody > < / table > < / td > < / tr > < tr > < td style = "border:none" > < i > j < sub > A< / sub > =< / i > < / td > < td style = "border:none" > < i > < code > Name< / code > (т.е . столбец 1)< / i > < / td > < td style = "border:none" > < i > j < sub > B< / sub > =< / i > < / td > < td style = "border:none" > < i > < code > Character< / code > (т.е . столбец 0)< / i > < / td > < / tr > < / tbody > < / table > < / td > < td style = "padding: 4px; margin: 5px;" > < / td > < / tr > < / tbody > < / table > < p > Вывод < / p > < table > < tbody > < tr > < th style = "padding: 4px; margin: 5px;" > A.Age < / th > < th style = "padding: 4px; margin: 5px;" > Имя < / th > < th style = "padding: 4px; margin: 5px;" > B.Character < / th > < th style = "padding: 4px; margin: 5px;" > B.Nemesis < / th > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 27 < / td > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Киты < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 27 < / td > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Иона < / td > < td style = "padding: 4px; margin: 5px;" > Пауки < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 18 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > привидения < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 18 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Zombies < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 28 < / td > < td style = "padding: 4px; margin: 5px;" > слава < / td > < td style = "padding: 4px; margin: 5px;" > слава < / td > < td style = "padding: 4px; margin: 5px;" > Buffy < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 28 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > привидения < / td > < / tr > < tr > < td style = "padding: 4px; margin: 5px;" > 28 < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Алан < / td > < td style = "padding: 4px; margin: 5px;" > Zombies < / td > < / tr > < / tbody > < / table > < p > < / p > < p > < / p > < p > Порядок строк в вых о дн<D0B4>
< / section >
2018-10-10 18:03:03 -04:00
## Instructions
2019-08-28 16:26:13 +03:00
< section id = 'instructions' >
Implement the "hash join" algorithm as a function and demonstrate that it passes the test-case listed below. The function should accept two arrays of objects and return an array of combined objects.
< h4 > < strong > Input< / strong > < / h4 >
< table >
< tr >
< td style = "padding: 4px; margin: 5px;" >
< table style = "border:none; border-collapse:collapse;" >
< tr >
< td style = "border:none" > < i > A =< / i >
< / td >
< td style = "border:none" >
< table >
< tr >
< th style = "padding: 4px; margin: 5px;" > Age < / th >
< th style = "padding: 4px; margin: 5px;" > Name
< / th > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 27 < / td >
< td style = "padding: 4px; margin: 5px;" > Jonah
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 18 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 28 < / td >
< td style = "padding: 4px; margin: 5px;" > Glory
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 18 < / td >
< td style = "padding: 4px; margin: 5px;" > Popeye
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 28 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan
< / td > < / tr > < / table >
< / td >
< td style = "border:none; padding-left:1.5em;" rowspan = "2" >
< / td >
< td style = "border:none" > < i > B =< / i >
< / td >
< td style = "border:none" >
< table >
< tr >
< th style = "padding: 4px; margin: 5px;" > Character < / th >
< th style = "padding: 4px; margin: 5px;" > Nemesis
< / th > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Whales
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Spiders
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Ghosts
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Zombies
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > Glory < / td >
< td style = "padding: 4px; margin: 5px;" > Buffy
< / td > < / tr > < / table >
< / td > < / tr >
< tr >
< td style = "border:none" > < i > j< sub > A< / sub > =< / i >
< / td >
< td style = "border:none" > < i > < code > Name< / code > (i.e. column 1)< / i >
< / td >
< td style = "border:none" > < i > j< sub > B< / sub > =< / i >
< / td >
< td style = "border:none" > < i > < code > Character< / code > (i.e. column 0)< / i >
< / td > < / tr > < / table >
< / td >
< td style = "padding: 4px; margin: 5px;" >
< / td > < / tr > < / table >
< h4 > < strong > Output< / strong > < / h4 >
< table >
< tr >
< th style = "padding: 4px; margin: 5px;" > A_age < / th >
< th style = "padding: 4px; margin: 5px;" > A_name < / th >
< th style = "padding: 4px; margin: 5px;" > B_character < / th >
< th style = "padding: 4px; margin: 5px;" > B_nemesis
< / th > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 27 < / td >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Whales
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 27 < / td >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Jonah < / td >
< td style = "padding: 4px; margin: 5px;" > Spiders
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 18 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Ghosts
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 18 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Zombies
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 28 < / td >
< td style = "padding: 4px; margin: 5px;" > Glory < / td >
< td style = "padding: 4px; margin: 5px;" > Glory < / td >
< td style = "padding: 4px; margin: 5px;" > Buffy
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 28 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Ghosts
< / td > < / tr >
< tr >
< td style = "padding: 4px; margin: 5px;" > 28 < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Alan < / td >
< td style = "padding: 4px; margin: 5px;" > Zombies
< / td > < / tr > < / table >
The order of the rows in the output table is not significant.
2018-10-10 18:03:03 -04:00
< / section >
## Tests
< section id = 'tests' >
```yml
tests:
2019-08-28 16:26:13 +03:00
- text: < code > hashJoin</ code > is a function.
testString: assert(typeof hashJoin === 'function');
- text: '< code > hashJoin([{ age: 27, name: "Jonah" }, { age: 18, name: "Alan" }, { age: 28, name: "Glory" }, { age: 18, name: "Popeye" }, { age: 28, name: "Alan" }], [{ character: "Jonah", nemesis: "Whales" }, { character: "Jonah", nemesis: "Spiders" }, { character: "Alan", nemesis: "Ghosts" }, { character:"Alan", nemesis: "Zombies" }, { character: "Glory", nemesis: "Buffy" }, { character: "Bob", nemesis: "foo" }])</ code > should return < code > [{"A_age": 27,"A_name": "Jonah", "B_character": "Jonah", "B_nemesis": "Whales"}, {"A_age": 27,"A_name": "Jonah", "B_character": "Jonah", "B_nemesis": "Spiders"}, {"A_age": 18,"A_name": "Alan", "B_character": "Alan", "B_nemesis": "Ghosts"}, {"A_age": 18,"A_name": "Alan", "B_character": "Alan", "B_nemesis": "Zombies"}, {"A_age": 28,"A_name": "Glory", "B_character": "Glory", "B_nemesis": "Buffy"}, {"A_age": 28,"A_name": "Alan", "B_character": "Alan", "B_nemesis": "Ghosts"}, {"A_age": 28,"A_name": "Alan", "B_character": "Alan", "B_nemesis": "Zombies"}]</ code > '
testString: assert.deepEqual(hashJoin(hash1, hash2), res);
2018-10-10 18:03:03 -04:00
```
< / section >
## Challenge Seed
< section id = 'challengeSeed' >
< div id = 'js-seed' >
```js
2019-08-28 16:26:13 +03:00
function hashJoin(hash1, hash2) {
2018-10-10 18:03:03 -04:00
// Good luck!
return [];
}
```
< / div >
2019-08-28 16:26:13 +03:00
### After Tests
2018-10-10 18:03:03 -04:00
< div id = 'js-teardown' >
```js
2019-08-28 16:26:13 +03:00
const hash1 = [
{ age: 27, name: 'Jonah' },
{ age: 18, name: 'Alan' },
{ age: 28, name: 'Glory' },
{ age: 18, name: 'Popeye' },
{ age: 28, name: 'Alan' }
];
const hash2 = [
{ character: 'Jonah', nemesis: 'Whales' },
{ character: 'Jonah', nemesis: 'Spiders' },
{ character: 'Alan', nemesis: 'Ghosts' },
{ character: 'Alan', nemesis: 'Zombies' },
{ character: 'Glory', nemesis: 'Buffy' },
{ character: 'Bob', nemesis: 'foo' }
];
const res = [
{ A_age: 27, A_name: 'Jonah', B_character: 'Jonah', B_nemesis: 'Whales' },
{ A_age: 27, A_name: 'Jonah', B_character: 'Jonah', B_nemesis: 'Spiders' },
{ A_age: 18, A_name: 'Alan', B_character: 'Alan', B_nemesis: 'Ghosts' },
{ A_age: 18, A_name: 'Alan', B_character: 'Alan', B_nemesis: 'Zombies' },
{ A_age: 28, A_name: 'Glory', B_character: 'Glory', B_nemesis: 'Buffy' },
{ A_age: 28, A_name: 'Alan', B_character: 'Alan', B_nemesis: 'Ghosts' },
{ A_age: 28, A_name: 'Alan', B_character: 'Alan', B_nemesis: 'Zombies' }
];
const bench1 = [{ name: 'u2v7v', num: 1 }, { name: 'n53c8', num: 10 }, { name: 'oysce', num: 9 }, { name: '0mto2s', num: 1 }, { name: 'vkh5id', num: 4 }, { name: '5od0cf', num: 8 }, { name: 'uuulue', num: 10 }, { name: '3rgsbi', num: 9 }, { name: 'kccv35r', num: 4 }, { name: '80un74', num: 9 }, { name: 'h4pp3', num: 6 }, { name: '51bit', num: 7 }, { name: 'j9ndf', num: 8 }, { name: 'vf3u1', num: 10 }, { name: 'g0bw0om', num: 10 }, { name: 'j031x', num: 7 }, { name: 'ij3asc', num: 9 }, { name: 'byv83y', num: 8 }, { name: 'bjzp4k', num: 4 }, { name: 'f3kbnm', num: 10 }];
const bench2 = [{ friend: 'o8b', num: 8 }, { friend: 'ye', num: 2 }, { friend: '32i', num: 5 }, { friend: 'uz', num: 3 }, { friend: 'a5k', num: 4 }, { friend: 'uad', num: 7 }, { friend: '3w5', num: 10 }, { friend: 'vw', num: 10 }, { friend: 'ah', num: 4 }, { friend: 'qv', num: 7 }, { friend: 'ozv', num: 2 }, { friend: '9ri', num: 10 }, { friend: '7nu', num: 4 }, { friend: 'w3', num: 9 }, { friend: 'tgp', num: 8 }, { friend: 'ibs', num: 1 }, { friend: 'ss7', num: 6 }, { friend: 'g44', num: 9 }, { friend: 'tab', num: 9 }, { friend: 'zem', num: 10 }];
2018-10-10 18:03:03 -04:00
```
< / div >
< / section >
## Solution
< section id = 'solution' >
```js
2019-08-28 16:26:13 +03:00
function hashJoin(hash1, hash2) {
const hJoin = (tblA, tblB, strJoin) => {
const [jA, jB] = strJoin.split('=');
const M = tblB.reduce((a, x) => {
const id = x[jB];
return (
a[id] ? a[id].push(x) : (a[id] = [x]),
a
);
}, {});
return tblA.reduce((a, x) => {
const match = M[x[jA]];
return match ? (
a.concat(match.map(row => dictConcat(x, row)))
) : a;
}, []);
};
const dictConcat = (dctA, dctB) => {
const ok = Object.keys;
return ok(dctB).reduce(
(a, k) => (a[`B_${k}` ] = dctB[k]) && a,
ok(dctA).reduce(
(a, k) => (a[`A_${k}` ] = dctA[k]) && a, {}
)
);
};
return hJoin(hash1, hash2, 'name=character');
}
2018-10-10 18:03:03 -04:00
```
2019-08-28 16:26:13 +03:00
2018-10-10 18:03:03 -04:00
< / section >