Skip to content

Commit

Permalink
application commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Alez87 committed Nov 9, 2019
0 parents commit 7510208
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 0 deletions.
14 changes: 14 additions & 0 deletions README.md
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.
186 changes: 186 additions & 0 deletions application_description.ipynb
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
}
4 changes: 4 additions & 0 deletions constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DEFAULT_ARRAY = [[1,2,[3]],4]

LOG_LEVEL = 'INFO'

51 changes: 51 additions & 0 deletions flatten_array.py
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()
26 changes: 26 additions & 0 deletions run_test
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

27 changes: 27 additions & 0 deletions unittest_flatten_array.py
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)

0 comments on commit 7510208

Please sign in to comment.