Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert item into case-insensitive sorted list in Python

I have a list of strings that is already sorted in case-insensitive order. I would like to insert a new string into the list. One way to do this is to append the item and then sort the list, like so:

myList.append('Something')
myList.sort(key=lambda s: s.lower())

But I was wondering if there is a way to just insert the item in the correct position without sorting the whole thing again.

I found this question: Insert an item into a sorted list in Python. It points towards Python's bisect module. But that module doesn't look like it can support case-insensitivity.


Edit: I tested out several of the answers listed here.

  • Appending the item to the end and sorting the whole list (as proposed in the original question) was the slowest.
  • Moinuddin Quadri's answer was faster than sorting the whole list, but it was still pretty slow, due to running lower() on every item on the list.
  • Stefan Pochmann's answer was an order of magnitude faster than sorting the whole list.
  • Jared Goguen's answer was the fastest for repeated insertions. The first time, though, it runs lower() on every element.

It was a close call to accept an answer. In the end, I went with Stefan Pochmann's answer because it was the best for a one-time insertion, and accessing the resulting list does not require accessing a member variable. However, use cases vary, so be sure to examine all the answers.

like image 785
Becca codes Avatar asked Jan 27 '17 21:01

Becca codes


People also ask

How do you make a list case insensitive in Python?

Approach No 1: Python String lower() Method This is the most popular approach to case-insensitive string comparisons in Python. The lower() method converts all the characters in a string to the lowercase, making it easier to compare two strings.

How do you ignore case sensitive in python?

We can ignore case in Python using the . upper() and . lower() methods.

How do you sort lowercase and uppercase in Python?

By default, the sort() method sorts the list in ASCIIbetical order rather than actual alphabetical order. This means uppercase letters come before lowercase letters. This causes the sort() function to treat all the list items as if they were lowercase without actually changing the values in the list.


2 Answers

It's a good opportunity to practice binary search again (or just copy&paste&modify bisect.insort, which is what I did):

def insort_case_insensitive(a, x):
    key = x.lower()
    lo, hi = 0, len(myList)
    while lo < hi:
        mid = (lo + hi) // 2
        if key < a[mid].lower():
            hi = mid
        else:
            lo = mid + 1
    a.insert(lo, x)

Demo:

myList = ['a', 'b', 'c', 'd', 'e']
for x in 'A', 'B', 'C', 'D', 'E':
    insort_case_insensitive(myList, x)
print myList

Prints:

['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E']

It's O(n), just like append+sort would be, but only because of the a.insert(lo, x) at the end. Which is dead-simple and done in C, so it's super fast. The binary search of course only takes O(log n) steps, so that's super fast as well. The append+sort way would call .lower() on all elements and compare them, both of which is much slower. @MoinuddinQuadri's first solution is also much slower because of calling .lower() on all elements.

See my other answer for a benchmarking comparison.

like image 181
Stefan Pochmann Avatar answered Oct 19 '22 16:10

Stefan Pochmann


You may use bisect.bisect on the lower-cased sorted list as:

from bisect import bisect
my_list = ["aa", "bb", "Dd", "ee"]
insert_string = "CC"

#                 convert all the items in list to lower case for
#               v finding the correct location via. bisect
index = bisect([i.lower() for i in my_list], insert_string.lower())
#                bisect based on lower-cased string for  ^
#                case-insensitive behavior

my_list.insert(index, insert_string)

where updated content of my_list will be:

['aa', 'bb', 'CC', 'Dd', 'ee']
like image 37
Moinuddin Quadri Avatar answered Oct 19 '22 17:10

Moinuddin Quadri