finished
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*__cache__*
|
||||||
|
*__pycache__*
|
||||||
|
.venv
|
||||||
|
.pytest_cache
|
||||||
43
README.md
Normal file
43
README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Nordhealth test
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Given an unsorted array A[]. The task is to print all unique pairs in the unsorted array with equal sum.
|
||||||
|
Note: Print the result in the format as shown in the below examples.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```
|
||||||
|
Input: A[] = { 6, 4, 12, 10, 22, 54, 32, 42, 21, 11}
|
||||||
|
Output:
|
||||||
|
Pairs : ( 4, 12) ( 6, 10) have sum : 16
|
||||||
|
Pairs : ( 10, 22) ( 21, 11) have sum : 32
|
||||||
|
Pairs : ( 12, 21) ( 22, 11) have sum : 33
|
||||||
|
Pairs : ( 22, 21) ( 32, 11) have sum : 43
|
||||||
|
Pairs : ( 32, 21) ( 42, 11) have sum : 53
|
||||||
|
Pairs : ( 12, 42) ( 22, 32) have sum : 54
|
||||||
|
Pairs : ( 10, 54) ( 22, 42) have sum : 64
|
||||||
|
```
|
||||||
|
```
|
||||||
|
Input:A[]= { 4, 23, 65, 67, 24, 12, 86}
|
||||||
|
Output:
|
||||||
|
Pairs : ( 4, 86) ( 23, 67) have sum : 90
|
||||||
|
```
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution in `nordhealth_test/solution.py:51` (print_pairs_with_same_sum())
|
||||||
|
|
||||||
|
Tests for the inputs are defined it `tests/test_solution.py`
|
||||||
|
|
||||||
|
For package manager I am using poetry, so to activate venv:
|
||||||
|
- `poetry install`
|
||||||
|
- `poetry env activate`
|
||||||
|
|
||||||
|
## Running
|
||||||
|
to run the solution:
|
||||||
|
- `chmod +x ./nordhealth_test/solution.py`
|
||||||
|
- `./nordhealth_test/solution.py [path to input file]`
|
||||||
|
- Example: `./nordhealth_test/solution.py ./inputs/input1.txt`
|
||||||
|
|
||||||
|
To run the tests:
|
||||||
|
- `pytest tests/`
|
||||||
1
inputs/input1.txt
Normal file
1
inputs/input1.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6,4,12,10,22,54,32,42,21,11
|
||||||
1
inputs/input2.txt
Normal file
1
inputs/input2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4,23,65,67,24,12,86
|
||||||
0
nordhealth_test/__init__.py
Normal file
0
nordhealth_test/__init__.py
Normal file
98
nordhealth_test/solution.py
Executable file
98
nordhealth_test/solution.py
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
from typing import List
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
"""
|
||||||
|
Given an unsorted array A[]. The task is to print all unique pairs in the unsorted array with equal sum.
|
||||||
|
Note: Print the result in the format as shown in the below examples.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
Input: A[] = { 6, 4, 12, 10, 22, 54, 32, 42, 21, 11}
|
||||||
|
Output:
|
||||||
|
Pairs : ( 4, 12) ( 6, 10) have sum : 16
|
||||||
|
Pairs : ( 10, 22) ( 21, 11) have sum : 32
|
||||||
|
Pairs : ( 12, 21) ( 22, 11) have sum : 33
|
||||||
|
Pairs : ( 22, 21) ( 32, 11) have sum : 43
|
||||||
|
Pairs : ( 32, 21) ( 42, 11) have sum : 53
|
||||||
|
Pairs : ( 12, 42) ( 22, 32) have sum : 54
|
||||||
|
Pairs : ( 10, 54) ( 22, 42) have sum : 64
|
||||||
|
|
||||||
|
Input:A[]= { 4, 23, 65, 67, 24, 12, 86}
|
||||||
|
Output:
|
||||||
|
Pairs : ( 4, 86) ( 23, 67) have sum : 90
|
||||||
|
"""
|
||||||
|
def main() -> None:
|
||||||
|
argc = len(sys.argv)
|
||||||
|
argv = sys.argv
|
||||||
|
if argc != 2:
|
||||||
|
raise ValueError("Invalid input. You need to provide a single path to the input file. \n Ex.: `./solution.py ./input1.txt`")
|
||||||
|
|
||||||
|
# Read input from the file and process the data
|
||||||
|
try:
|
||||||
|
input_data = read_input(argv[1])
|
||||||
|
print_pairs_with_same_sum(input_data)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def read_input(input_file: str) -> List[int]:
|
||||||
|
""" Reads the input file and returns a list of integers. """
|
||||||
|
try:
|
||||||
|
with open(input_file, "r") as file:
|
||||||
|
lst = file.readline().split(',')
|
||||||
|
parsed = [int(x.strip()) for x in lst]
|
||||||
|
return parsed
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Failed to read or parse the file: {e}")
|
||||||
|
|
||||||
|
def print_pairs_with_same_sum(arr: List[int]) -> None:
|
||||||
|
"""
|
||||||
|
Solution to the problem. Since performance is required it's in one method, but could be separated:
|
||||||
|
1). Calculate the sums into a hashmap and add the pairs
|
||||||
|
2). print the result
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Not a valid array
|
||||||
|
if len(arr) < 2:
|
||||||
|
print("No pairs can be formed from the input file.")
|
||||||
|
|
||||||
|
sum_map = defaultdict(list)
|
||||||
|
|
||||||
|
# Check for duplicate pairs.
|
||||||
|
seen_pairs = set()
|
||||||
|
|
||||||
|
n = len(arr)
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
# Time Complexity (O(n^2)), as we have n(n-1)/2 for the second loop.
|
||||||
|
for j in range(i + 1, n):
|
||||||
|
current_sum = arr[i] + arr[j]
|
||||||
|
pair = tuple((arr[i], arr[j]))
|
||||||
|
|
||||||
|
if pair not in seen_pairs:
|
||||||
|
# This will output nothing for [2,2,2,2]. Depending on the requirements we can store the pair using indices,
|
||||||
|
# then the result would be:
|
||||||
|
# (A[0],A[1]) (A[0],A[2]) (A[0],A[3]) (A[1],A[2]) (A[1],A[3]) (A[2],A[3]) - sum: 4
|
||||||
|
# And we will not need the seen_pairs set.
|
||||||
|
sum_map[current_sum].append(pair)
|
||||||
|
seen_pairs.add(pair)
|
||||||
|
|
||||||
|
# This is required to follow the example output, as it is presented as sorted by sum in the task description.
|
||||||
|
# We can skip the sorting if this is not really part of the requiremetns.
|
||||||
|
for sum_val in sorted(sum_map.keys()):
|
||||||
|
pairs = sum_map[sum_val]
|
||||||
|
|
||||||
|
if len(pairs) > 1:
|
||||||
|
pairs.sort()
|
||||||
|
|
||||||
|
print(f"Pairs : ", end="")
|
||||||
|
for pair in pairs:
|
||||||
|
print(f"( {pair[0]}, {pair[1]})", end=" ")
|
||||||
|
print(f"have sum : {sum_val}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
80
poetry.lock
generated
Normal file
80
poetry.lock
generated
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
markers = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.1.0"
|
||||||
|
description = "brain-dead simple config-ini parsing"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
|
||||||
|
{file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "24.2"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
|
||||||
|
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.5.0"
|
||||||
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
||||||
|
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "8.3.5"
|
||||||
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"},
|
||||||
|
{file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||||
|
iniconfig = "*"
|
||||||
|
packaging = "*"
|
||||||
|
pluggy = ">=1.5,<2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "2.1"
|
||||||
|
python-versions = ">=3.13"
|
||||||
|
content-hash = "8ef1d528c82ebf4a734833eed980b6b031e288bf5563655b512f75969b90d60a"
|
||||||
20
pyproject.toml
Normal file
20
pyproject.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[project]
|
||||||
|
name = "nordhealth-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = [
|
||||||
|
{name = "viktor",email = "me@vpanteleev.com"}
|
||||||
|
]
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.poetry]
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
pytest = "^8.3.5"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
55
tests/test_solution.py
Normal file
55
tests/test_solution.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
from nordhealth_test.solution import print_pairs_with_same_sum
|
||||||
|
|
||||||
|
def capture_output(func, *args, **kwargs):
|
||||||
|
captured_output = StringIO()
|
||||||
|
sys.stdout = captured_output
|
||||||
|
func(*args, **kwargs)
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
return captured_output.getvalue()
|
||||||
|
|
||||||
|
# Test case Input 1: [6, 4, 12, 10, 22, 54, 32, 42, 21, 11]
|
||||||
|
def test_input_1():
|
||||||
|
arr = [6, 4, 12, 10, 22, 54, 32, 42, 21, 11]
|
||||||
|
expected_output = (
|
||||||
|
"Pairs : ( 4, 12) ( 6, 10) have sum : 16\n"
|
||||||
|
"Pairs : ( 10, 22) ( 21, 11) have sum : 32\n"
|
||||||
|
"Pairs : ( 12, 21) ( 22, 11) have sum : 33\n"
|
||||||
|
"Pairs : ( 22, 21) ( 32, 11) have sum : 43\n"
|
||||||
|
"Pairs : ( 32, 21) ( 42, 11) have sum : 53\n"
|
||||||
|
"Pairs : ( 12, 42) ( 22, 32) have sum : 54\n"
|
||||||
|
"Pairs : ( 10, 54) ( 22, 42) have sum : 64\n"
|
||||||
|
)
|
||||||
|
result = capture_output(print_pairs_with_same_sum, arr)
|
||||||
|
assert result == expected_output
|
||||||
|
|
||||||
|
# Test case Input 2: [4, 23, 65, 67, 24, 12, 86]
|
||||||
|
def test_input_2():
|
||||||
|
arr = [4, 23, 65, 67, 24, 12, 86]
|
||||||
|
expected_output = (
|
||||||
|
"Pairs : ( 4, 86) ( 23, 67) have sum : 90\n"
|
||||||
|
)
|
||||||
|
result = capture_output(print_pairs_with_same_sum, arr)
|
||||||
|
assert result == expected_output
|
||||||
|
|
||||||
|
# Test case: Array with no valid pairs
|
||||||
|
def test_no_valid_pairs():
|
||||||
|
arr = [1, 2, 3, 5]
|
||||||
|
expected_output = ""
|
||||||
|
result = capture_output(print_pairs_with_same_sum, arr)
|
||||||
|
assert result == expected_output
|
||||||
|
|
||||||
|
# Test case: Array with exactly one element
|
||||||
|
def test_single_element():
|
||||||
|
arr = [10]
|
||||||
|
expected_output = "No pairs can be formed from the input file.\n"
|
||||||
|
result = capture_output(print_pairs_with_same_sum, arr)
|
||||||
|
assert result == expected_output
|
||||||
|
|
||||||
|
# Test case: Empty array
|
||||||
|
def test_empty_array():
|
||||||
|
arr = []
|
||||||
|
expected_output = "No pairs can be formed from the input file.\n"
|
||||||
|
result = capture_output(print_pairs_with_same_sum, arr)
|
||||||
|
assert result == expected_output
|
||||||
Reference in New Issue
Block a user