-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7510208
Showing
6 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
The provided answer is based on a recursive solution that will scan and go deeper into the input array, until a primitive value is found. | ||
|
||
For a more detailed explanation please refer to the Jupiter notebook file 'application_description.ipynb' | ||
|
||
Automated tests code inside the file 'unittest_flatten_array.py' | ||
To run the automated test, execute the script run_test.sh: | ||
bash run_test | ||
|
||
How to run the code: | ||
python3 array_to_flatten.py [options] array | ||
es: python3 flatten_array.py '[[1, 2, [3]], 4]' | ||
The array attribute is optional. If not specified, is considered the default list [[1,2,[3]],4] | ||
|
||
Code tested on Python 3.7.3. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"- setup_log() is a function used to create the handler to send logging output to stream\n", | ||
"- remove_handler() has been introduced only for the Jupyter notebook in order to be able to run the application multiple times and refresh logs every time, thus avoiding to restart the Jupyter kernel every time" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import logging\n", | ||
"log = logging.getLogger()\n", | ||
"handler = logging.StreamHandler()\n", | ||
"\n", | ||
"def setup_log():\n", | ||
" log.setLevel(c.LOG_LEVEL)\n", | ||
" handler.setFormatter(logging.Formatter(\"%(asctime)s [%(levelname)s]: %(message)s\"))\n", | ||
" log.addHandler(handler)\n", | ||
" \n", | ||
"def remove_handler():\n", | ||
" log.removeHandler(handler)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"convert_string_array() convert a string into a list by using the json.loads() function that deserialize a string into a list." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import json\n", | ||
"def convert_string_array(s):\n", | ||
" array_input = json.loads(s)\n", | ||
" log.info('Array to flatten inserted as parameter: ' + str(array_input))\n", | ||
" return array_input" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"get_array_to_flatten() tries to convert the inserted string into list, otherwise it load from the constants.py file.\n", | ||
"If there is an argument but is malformed, it raises an error.\n", | ||
"\n", | ||
"- Jupyter notebook does not support argv, so I enter a random string\n", | ||
"- json.decoder.JSONDecodeError has been added to handle the JSONDecodeError inside Jupiter notebook." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 20, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import constants as c\n", | ||
"\n", | ||
"def get_array_to_flatten():\n", | ||
" try:\n", | ||
" return convert_string_array('wrong argv')\n", | ||
" except (IndexError, json.decoder.JSONDecodeError):\n", | ||
" log.info('Array to flatten not inserted as parameters. I use the default: ' + str(c.DEFAULT_ARRAY)) \n", | ||
" return c.DEFAULT_ARRAY\n", | ||
" except Error as e:\n", | ||
" print(e)\n", | ||
" log.error('Error during parsing the input array. Please check it.')\n", | ||
" log.error('Possible causes: param not string; bad formatted array.')\n", | ||
" return ''" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"modify_array() is the recursive function used to loop over the input array and calculate the flattened array:\n", | ||
"- if the elemenet is a primitive I insert into the final array\n", | ||
"- otherwise a continue digging deeper into the array" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"def modify_array(array_to_flatten, array_flattened):\n", | ||
" for element in array_to_flatten:\n", | ||
" if isinstance(element, list):\n", | ||
" log.info('Element ' + str(element) + ' is an array so I go deeper inside.')\n", | ||
" modify_array(element, array_flattened)\n", | ||
" else:\n", | ||
" log.info('Element ' + str(element) + ' is a primitive so I add it to the final array.')\n", | ||
" array_flattened.append(element)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"main function for the application" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"def main():\n", | ||
" array_final = []\n", | ||
" array_to_flatten = get_array_to_flatten()\n", | ||
" print(array_to_flatten)\n", | ||
" if array_to_flatten:\n", | ||
" modify_array(array_to_flatten, array_final)\n", | ||
" log.info('Array flattened: ' + str(array_final))\n", | ||
" return array_final #for unit tests" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 24, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stderr", | ||
"output_type": "stream", | ||
"text": [ | ||
"2019-11-06 14:37:41,712 [INFO]: Array to flatten not inserted as parameters. I use the default: [[1, 2, [3]], 4]\n", | ||
"2019-11-06 14:37:41,714 [INFO]: Element [1, 2, [3]] is an array so I go deeper inside.\n", | ||
"2019-11-06 14:37:41,715 [INFO]: Element 1 is a primitive so I add it to the final array.\n", | ||
"2019-11-06 14:37:41,716 [INFO]: Element 2 is a primitive so I add it to the final array.\n", | ||
"2019-11-06 14:37:41,717 [INFO]: Element [3] is an array so I go deeper inside.\n", | ||
"2019-11-06 14:37:41,718 [INFO]: Element 3 is a primitive so I add it to the final array.\n", | ||
"2019-11-06 14:37:41,719 [INFO]: Element 4 is a primitive so I add it to the final array.\n", | ||
"2019-11-06 14:37:41,719 [INFO]: Array flattened: [1, 2, 3, 4]\n" | ||
] | ||
}, | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"[[1, 2, [3]], 4]\n", | ||
"[1, 2, 3, 4]\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"setup_log()\n", | ||
"print(main())\n", | ||
"remove_handler()" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.6.6" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
DEFAULT_ARRAY = [[1,2,[3]],4] | ||
|
||
LOG_LEVEL = 'INFO' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import sys | ||
import logging | ||
import json | ||
|
||
import constants as c | ||
|
||
log = logging.getLogger() | ||
|
||
def setup_log(): | ||
log.setLevel(c.LOG_LEVEL) | ||
handler = logging.StreamHandler() | ||
handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s]: %(message)s")) | ||
log.addHandler(handler) | ||
|
||
def convert_string_array(s): | ||
array_input = json.loads(s) | ||
log.info('Array to flatten inserted as parameter: ' + str(array_input)) | ||
return array_input | ||
|
||
def get_array_to_flatten(): | ||
try: | ||
return convert_string_array(sys.argv[1]) | ||
except IndexError: | ||
log.info('Array to flatten not inserted as parameters. I use the default: ' + str(c.DEFAULT_ARRAY)) | ||
return c.DEFAULT_ARRAY | ||
except ValueError: | ||
log.error('Error during parsing the input array. Please check it.') | ||
log.error('Possible causes: param not string; bad formatted array.') | ||
return '' | ||
# exit(-1) | ||
|
||
def modify_array(array_to_flatten, array_flattened): | ||
for element in array_to_flatten: | ||
if isinstance(element, list): | ||
log.info('Element ' + str(element) + ' is an array so I go deeper inside.') | ||
modify_array(element, array_flattened) | ||
else: | ||
log.info('Element ' + str(element) + ' is a primitive so I add it to the final array.') | ||
array_flattened.append(element) | ||
|
||
def main(): | ||
array_final = [] | ||
array_to_flatten = get_array_to_flatten() | ||
if array_to_flatten: | ||
modify_array(array_to_flatten, array_final) | ||
log.info('Array flattened: ' + str(array_final)) | ||
return array_final #for unit tests | ||
|
||
if __name__ == "__main__": | ||
setup_log() | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/bin/bash | ||
|
||
# Tests format: python3 <unittest_file> <INPUT> <TARGET> | ||
|
||
TARGET='[1,2,3,4]' | ||
python3 unittest_flatten_array.py $TARGET #default input array | ||
|
||
INPUT='[[1,2,[3]],4]' | ||
TARGET='[1,2,3,4]' | ||
python3 unittest_flatten_array.py $INPUT $TARGET | ||
|
||
#empty array | ||
INPUT='[]' | ||
TARGET='[]' | ||
python3 unittest_flatten_array.py $INPUT $TARGET | ||
|
||
INPUT='[[1,[2,3,[4]],5,6],7]' | ||
TARGET='[1,2,3,4,5,6,7]' | ||
python3 unittest_flatten_array.py $INPUT $TARGET | ||
|
||
#bad formatted array | ||
INPUT='[[1,[2-3,[3]]],4]' | ||
TARGET='[]' | ||
#python3 unittest_flatten_array.py '[[1,[2 [3]]],4]' '[]' | ||
python3 unittest_flatten_array.py $INPUT $TARGET | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import unittest | ||
import sys | ||
import importlib | ||
import json | ||
|
||
TARGET = importlib.import_module('flatten_array') | ||
|
||
def checkEqual(L1, L2): | ||
return len(L1) == len(L2) and sorted(L1) == sorted(L2) | ||
|
||
class TestFlattenArray(unittest.TestCase): | ||
|
||
ARRAY = [] | ||
|
||
def test_array(self): | ||
result = TARGET.main() | ||
target_array=json.loads(self.ARRAY) | ||
print('result: ' + str(result)) | ||
print('array: ' + str(target_array)) | ||
self.assertTrue(type(result) is list) | ||
self.assertTrue(checkEqual(result, target_array)) | ||
|
||
if __name__ == '__main__': | ||
# unittest.main(argv=['TestFlattenArray.test_empty_array ']+sys.argv[2:], exit=False) | ||
if len(sys.argv) > 1: | ||
TestFlattenArray.ARRAY = sys.argv.pop() | ||
unittest.main(argv=['TestFlattenArray.test_empty_array ']+sys.argv[2:], exit=False) |