Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,5 @@ Interview Questions
- [Task #3](src/interview/create-message-handler) - _Create Message Handler_
- [Task #4](src/interview/create-channel-message-handler) - _Create Channel Message Handler_
- [Task #5](src/interview/create-smart-fetch) - _Create Smart Fetch_
- [Task #6](src/interview/time-limited-cache) - _Time Limited Cache_
- [Task #6](src/interview/time-limited-cache) - _Time Limited Cache_
- [Task #7](src/interview/concat-sources-blocks/global-type-and-title) - _Concat Sources Blocks: Global Type & Title_
4 changes: 4 additions & 0 deletions src/interview/concat-sources-blocks/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Block {
type: string;
title: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { concatSourcesBlocks } from './solution';

describe('Concat Sources Blocks: Global Type & Title | Interview | Testcases', () => {
test('#1', () => {
const primary = [
{ type: 'спорт', title: 'Матч' },
{ type: 'экономика', title: 'Курс валют' },
];
const secondary = [
{ type: 'политика', title: 'Главная новость' },
{ type: 'культура', title: 'Главная новость' },
];
const orders = ['экономика', 'политика', 'культура', 'спорт'];
const result = concatSourcesBlocks(primary, secondary, orders);
const expected = [
{ type: 'экономика', title: 'Курс валют' },
{ type: 'политика', title: 'Главная новость' },
{ type: 'спорт', title: 'Матч' },
];
expect(result).toEqual(expected);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Block } from '../common';

/**
* @param primaryBlocks - blocks from main source
* @param secondaryBlocks - blocks from secondary sources
* @param orders - requested types in order
* @returns array of blocks, ordered by `orders`, without repeats in `types `or `titles`.
* Primary blocks are in priority.
*/
export const concatSourcesBlocks = (
primaryBlocks: Block[],
secondaryBlocks: Block[],
orders: string[],
): Block[] => {
const result: Block[] = [];
const usedTitles = new Set<string>();
const usedTypes = new Set<string>();

const groupByType = (blocks: Block[]): Map<string, Set<Block>> => {
const map = new Map<string, Set<Block>>();
for (const block of blocks) {
const group = map.get(block.type) ?? new Set<Block>();
group.add(block);
map.set(block.type, group);
}
return map;
};

const primaryMap = groupByType(primaryBlocks);
const secondaryMap = groupByType(secondaryBlocks);

const tryToAdd = (blocks: Set<Block> | undefined): boolean => {
if (!blocks) {
return false;
}
for (const block of blocks) {
if (!usedTitles.has(block.title) && !usedTypes.has(block.type)) {
result.push(block);
usedTypes.add(block.type);
usedTitles.add(block.title);
blocks.delete(block);
return true;
}
blocks.delete(block);
}
return false;
};

for (const order of orders) {
if (!tryToAdd(primaryMap.get(order))) {
tryToAdd(secondaryMap.get(order));
}
}

return result;
};
Loading