42

Here is my code, but I want a better solution, how do you think about the problem?

def get_all_substrings(string):
  length = len(string)
  alist = []
  for i in xrange(length):
    for j in xrange(i,length):
      alist.append(string[i:j + 1]) 
  return alist

print get_all_substring('abcde')
3
  • 1
    Better in what sense and what is the problem with this solution? Commented Mar 18, 2014 at 3:57
  • Maybe more faster? Or not so simple. Commented Mar 18, 2014 at 3:59
  • @user2357112, OP's native language is obviously not English, and it seems like OP is saying "or maybe it's not so simple to make this function faster". Commented Apr 10, 2019 at 12:32

9 Answers 9

48

The only improvement I could think of is, to use list comprehension like this

def get_all_substrings(input_string):
  length = len(input_string)
  return [input_string[i:j+1] for i in xrange(length) for j in xrange(i,length)]

print get_all_substrings('abcde')

The timing comparison between, yours and mine

def get_all_substrings(string):
  length = len(string)
  alist = []
  for i in xrange(length):
    for j in xrange(i,length):
      alist.append(string[i:j + 1]) 
  return alist

def get_all_substrings_1(input_string):
  length = len(input_string)
  return [input_string[i:j + 1] for i in xrange(length) for j in xrange(i,length)]

from timeit import timeit
print timeit("get_all_substrings('abcde')", "from __main__ import get_all_substrings")
# 3.33308315277
print timeit("get_all_substrings_1('abcde')", "from __main__ import get_all_substrings_1")
# 2.67816185951
Sign up to request clarification or add additional context in comments.

4 Comments

If you're doing timeit, you might find range is quicker than xrange for such a small range
@gnibbler I get slightly bigger number when I use range :(
@thefourtheye, don't be sad - it's a good thing if there isn't any longer a penalty to using xrange for small ranges (apart from the Python3 thing)
I'm guessing the time complexity of this is O(n log n)?
18

can be done concisely with itertools.combinations

from itertools import combinations

def get_all_substrings_2(string):
    length = len(string) + 1
    return [string[x:y] for x, y in combinations(range(length), r=2)]

1 Comment

This is much more performant than the currently selected answer too.
10

You could write it as a generator to save storing all the strings in memory at once if you don't need to

def get_all_substrings(string):
    length = len(string)
    for i in xrange(length):
        for j in xrange(i + 1, length + 1):
            yield(string[i:j]) 

for i in get_all_substrings("abcde"):
    print i

you can still make a list if you really need one

alist = list(get_all_substrings("abcde"))

The function can be reduced to return a generator expression

def get_all_substrings(s):
    length = len(s)
    return (s[i: j] for i in xrange(length) for j in xrange(i + 1, length + 1))

Or of course you can change two characters to return a list if you don't care about memory

def get_all_substrings(s):
    length = len(s)
    return [s[i: j] for i in xrange(length) for j in xrange(i + 1, length + 1)]

1 Comment

This saved me, I was getting a memory error, I did some searching, found your solution and it solved my issue as well. Thank you.
7

I've never been fond of range(len(seq)), how about using enumerate and just using the index value:

def indexes(seq, start=0):
    return (i for i,_ in enumerate(seq, start=start))

def gen_all_substrings(s):
    return (s[i:j] for i in indexes(s) for j in indexes(s[i:], i+1))

def get_all_substrings(string):
    return list(gen_all_substrings(string))

print(get_all_substrings('abcde'))

Comments

4

Python 3

s='abc'
list(s[i:j+1] for i in range (len(s)) for j in range(i,len(s)))

['a', 'ab', 'abc', 'b', 'bc', 'c']

1 Comment

This duplicates other answers. Have you added anything to the top 2 answers from 2-4 years ago?
1

Use itertools.permutations to generate all pairs of possible start and end indexes, and filter out only those where the start index is less than then end index. Then use these pairs to return slices of the original string.

from itertools import permutations

def gen_all_substrings(s):
    lt = lambda pair: pair[0] < pair[1]
    index_pairs = filter(lt, permutations(range(len(s)+1), 2))
    return (s[i:j] for i,j in index_pairs)

def get_all_substrings(s):
    return list(gen_all_substrings(s))

print(get_all_substrings('abcde'))

Comments

0

Another solution:

def get_all_substrings(string):
   length = len(string)+1
   return [string[x:y] for x in range(length) for y in range(length) if string[x:y]]

print get_all_substring('abcde')

Comments

0

Another solution using 2-D matrix approach

p = "abc"
a = list(p)
b = list(p)
c = list(p)
count = 0
for i in range(0,len(a)):
       dump = a[i]
            for j in range(0, len(b)):
                if i < j:
                    c.append(dump+b[j])
                    dump = dump + b[j]  

Comments

0

If you want to get the substrings sorted by the length:

s = 'abcde'
def allSubstrings(s: str) -> List[str]:
    length = len(s)
    mylist = []
    for i in range(1, length+1):
        for j in range(length-i+1):
            mylist.append(s[j:j+i])
    return mylist

print(allSubstrings(s))

['a', 'b', 'c', 'd', 'e', 'ab', 'bc', 'cd', 'de', 'abc', 'bcd', 'cde', 'abcd', 'bcde', 'abcde']

1 Comment

Comprehensions are significantly faster than loops.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.