Calling a dictionary a list is very confusing
Rather than using
min
, you could usesorted
.This'll change the time complexity of your code from \$O(n^2)\$ to \$O(n \log n)\$, as Python uses the Timsort. And since
sorted
is written in C, it'll be super fast too.Sorted also has the keyword argument
key
, which lets you sort by another value, rather than the value you get.This also keeps the original dictionary intact.
You can use
dict
andenumerate
to build your input list. And to build a list to pass toenumerate
you could usestr.split
.
And so I'd change your code to:
def sort_dict_by_value_len(dict_):
return sorted(dict_.items(), key=lambda kv: (len(kv[1]), kv[0]))
def sort_dict_by_value_len_without_key(dict_):
return [(k, dict_[k]) for _, k in sorted((len(v), k) for (k, v) in dict_.items())]
dict_ = dict(enumerate('one two three four five six seven eight nine ten'.split(), start=1))
for key, value in sort_dict_by_value_len(dict_):
print(key, value)
If you only want \$O(1)\$ memory usage, then you could use an insertion sort. But keeps the \$O(n^2)\$ time complexity. I also cheated a bit.
- I used a generator comprehension, rather than a list comprehension to ensure \$O(1)\$ space. Alternately, you could invert the algorithm, and pop from one array to another.
- I used
bisect.insort
to remove most of the logic.
def sort_dict_by_value_len(dict_):
output = []
while dict_:
key, value = dict_.popitem()
bisect.insort(output, ((len(value), key), (key, value)))
return (i[1] for i in output)