Last active
April 25, 2019 08:49
-
-
Save oz123/3e371b8c1c4c6d24752edede126156ca to your computer and use it in GitHub Desktop.
Flatten a list of lists in Python and Go
This file contains hidden or 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
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
) | |
func flatten(s []interface{}) (r []int) { | |
// type switch already discussed in the tour of go | |
for _, item := range s { | |
switch item := item.(type) { | |
// json.Unmarshal reads numbers as float64 | |
case float64: | |
r = append(r, int(item)) | |
case []interface{}: | |
r = append(r, flatten(item)...) | |
} | |
} | |
return | |
} | |
func main() { | |
// declaring n dimensional lists (slices) in go isn't easy | |
// stuffing them in json is a work around | |
var parsedList []interface{} | |
list2d := `[[111,222,333],[444,555,[666]], [777,888,999]]` | |
err := json.Unmarshal([]byte(list2d), &parsedList) | |
if err != nil { | |
fmt.Println(err) | |
} | |
fmt.Println(flatten(parsedList)) | |
} |
This file contains hidden or 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
# Python is still my first go to language for such a task | |
# There are many ways to reach the goal of this task. | |
# If I would not have to consider readability I would implement | |
# this task in a more functional style. However, I came to realize | |
# that my *personal* love of FP, isn't always compatible with what | |
# most people learn at university and practice daily (OOP). | |
# Hence, using Generators in Python is a good middle between achieving | |
# good readability of the code and good performance. | |
# | |
# i.e the following SO solution | |
# | |
# flatten = lambda lst: [lst] if type(lst) is int else reduce(operator.concat, | |
# [flatten(ele) for ele in lst]) | |
# | |
# super cool oneline, most Python beginners and even experiecned Python | |
# programmers will find it hard to understand without first reading the | |
# documentation for operator.concat and reduce. | |
# Also, this one-liner does not handle exceptions, see below a "safe version". | |
def flatten(_list): | |
""" | |
A version of flatten which doesn't handle non-iterable types | |
""" | |
for item in _list: | |
if isinstance(item, (list, tuple)): | |
for elem in flatten(item): | |
yield elem | |
else: | |
yield item | |
def safe_flatten(_list): | |
""" | |
A safe version of flatten which doesn't explode on weired inputs | |
""" | |
try: | |
for item in _list: | |
if isinstance(item, (list, tuple)): | |
for elem in safe_flatten(item): | |
yield elem | |
else: | |
yield item | |
except TypeError: | |
yield _list | |
# a full test suite with pytest or unittest is not required here | |
if __name__ == '__main__': | |
# some test data | |
test_data = ( | |
([[1, 2, [3]], 4], [1, 2, 3, 4]), | |
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], list(range(1, 11))), | |
([[1], [[2, 3]], [[4, [5], [6, 7, [8, [9, [10], ]]]], ]], list(range(1, 11))), | |
([1, ], [1, ]), | |
(1, [1, ]), | |
(None, [None]) # a weired test case | |
) | |
for test_pair in test_data: | |
try: | |
result = list(flatten(test_pair[0])) | |
except TypeError: | |
continue | |
try: | |
assert result == test_pair[1] | |
except AssertionError: | |
print("Want: ", result, "Got: ", test_pair[1]) | |
break | |
for test_pair in test_data: | |
result = list(safe_flatten(test_pair[0])) | |
try: | |
assert result == test_pair[1] | |
except AssertionError: | |
print("Want: ", result, "Got: ", test_pair[1]) | |
break |
This file contains hidden or 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
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"reflect" | |
"testing" | |
) | |
func TestSimpleList(t *testing.T) { | |
var parsedList []interface{} | |
list := `[1,2,3,4,5]` | |
//list2d := `[[111,222,333],[444,555,666], [777,888,999]]` | |
//listNd := `[[111,222,333],[444,555,666], [777,888,999,[1,2,3,[4,[5,6,[7]]]]]]` | |
err := json.Unmarshal([]byte(list), &parsedList) | |
if err != nil { | |
fmt.Println(err) | |
} | |
got := flatten(parsedList) | |
want := []int{1, 2, 3, 4, 5} | |
if !reflect.DeepEqual(want, got) { | |
t.Fatalf("Wanted %v, got %v", want, got) | |
} | |
} | |
func Test2dList(t *testing.T) { | |
var parsedList []interface{} | |
list2d := `[[111,222,333],[444,555,666], [777,888,999]]` | |
//listNd := `[[111,222,333],[444,555,666], [777,888,999,[1,2,3,[4,[5,6,[7]]]]]]` | |
err := json.Unmarshal([]byte(list2d), &parsedList) | |
if err != nil { | |
fmt.Println(err) | |
} | |
got := flatten(parsedList) | |
want := []int{111, 222, 333, 444, 555, 666, 777, 888, 999} | |
if !reflect.DeepEqual(want, got) { | |
t.Fatalf("Wanted %v, got %v", want, got) | |
} | |
} | |
func TestNdList(t *testing.T) { | |
var parsedList []interface{} | |
listNd := `[[1,2,3],[4,5,6], [7,8,9,[10,11,12,[13,[14,15,[16]]]]]]` | |
err := json.Unmarshal([]byte(listNd), &parsedList) | |
if err != nil { | |
fmt.Println(err) | |
} | |
got := flatten(parsedList) | |
want := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} | |
if !reflect.DeepEqual(want, got) { | |
t.Fatalf("Wanted %v, got %v", want, got) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment