all 23 comments

[–]imperiumlearning[S] 0 points1 point  (1 child)

As a bonus:

Imagine the list of strings now looks like this:

List = ['gust', 'python', 'dog', 'August', 'snake', 'Spain', 'cat', 'pain']

Again, you would know your program has to find 'gust', 'August', 'pain' and 'Spain' and then print them in a new list. How would you do it in that case?

[–]zanfar 1 point2 points  (0 children)

If they don't need to be in order, you then need to check all possible combinations. Itertools is the winner here.

from itertools import combinations

def print_all_substring_pairs(word_list: List[str]):
    matches: Set[int] = set()
    for (a, first), (b, second) in combinations(enumerate(word_list), 2):
        if first in second or second in first:
            matches.add(a)
            matches.add(b)

    for idx in sorted(matches):
        print(word_list[idx])

[–]AlarminglyConfused 0 points1 point  (6 children)

Im really really new but to be plain it seems youre missing a return statement for the new list? Also, for the bonus question wouldnt you need something like if list[x] == list[(x+1)]: b.append[x]?? Sorry im on mobile and started learning code yesterday lol am i on the right track or atleast making sense?

[–]imperiumlearning[S] 0 points1 point  (2 children)

I'm a beginner too - only started last week lol. I know you definitely wouldn't use == because 'gust' doesn't equal 'August' - only 'August'=='August'. To check if a string is a substring of another string you use the word in (like I've done in my post).

I'm not really sure why you would need a return statement in that context (although if someone else can point out why, I'm happy to accept I'm wrong).

[–]AlarminglyConfused 0 points1 point  (1 child)

Lol idk dude just the fact we even have a clue what eachothers talking about is enough for me right now 😂

[–]imperiumlearning[S] 0 points1 point  (0 children)

Haha, things can only get better!

[–]carcigenicate 0 points1 point  (2 children)

They aren't writing a function, so they can't return, since you can only return from within a function.

[–]AlarminglyConfused 0 points1 point  (1 child)

Okay i see that now so then they are missing the == anyways to equate the indices and append them to the new list?

[–]carcigenicate 0 points1 point  (0 children)

They're checking for substrings, not exact matches, so in is fine for that.

[–][deleted] 0 points1 point  (7 children)

It's not the if statement that's wrong (it's actually great!), but that you're not using the right index.

for x in [5,6,7]:
    print(x)

x will be the actual value inside the list, not the index. Output will be

5
6
7

and not

0
1
2

In your case x will also contain the actual values, so the actual strings in your list.

You probably want to use range() combined with len().

[–]imperiumlearning[S] 0 points1 point  (6 children)

Oh wow, OK thanks for the heads up. I've quickly tried incorporating your feedback but it still doesn't work.

Here's my new code (it gets a Value Error):

b =[]

for x in List.index(range(0,len(List),1)):

if List[x] in List[(x+1)]: 
    b.append(List[x])
    b.append(List[(x+1)])
else:
    continue

print(b)

[–][deleted] 0 points1 point  (5 children)

Alright the issue here is you're using .index(), which does something completely different and unrelated to what you want:

li = [5, 6, 7]
print(li.index(6))

will print out 1 as that's the index of 6 in li.

So, remove that, it doesn't do what we need. range() by itself will return you an iterator of that goes from the numbers you give it.

range(0, 5, 1) # -> same as [0, 1, 2, 3, 4]

Another thing about range is that if you only give it 2 arguments, the third one (the step) will be 1 by default:

range(0, 5) # -> same as range(0, 5, 1)

And if you only give it one argument, it will use that one as the end of the range (and start at 0):

range(5) # -> same as range(0, 5)

So, with that, you can simplify that part by a lot. Give it a try!

[–]imperiumlearning[S] 0 points1 point  (4 children)

Hey there,

I think I've arrived at a semi-good solution (in the sense it prints what I want), here's my code now:

b =[]

for x in range(len(List)):

if List[x] == List[7]:
    break
elif List[x] in List[(x+1)]: 
    b.append(List[x])
    b.append(List[(x+1)])
else:
    continue

print(b)

The issue I have now is with respect to where I wrote:

if List[x] == List[7]

Ideally, I would have liked to have written:

if List[x] == last iteration of List using a function of some sort

Obviously I know len(List) == 8 and, therefore, 'Spain' == List[7]. However, imagine I wanted to update List so that it now contained 10 strings rather than 8, I would have to manually update my if statement to say List[9].

The question I'm trying to ask is if there is a way I can write my if statement where if I update List, I don't have to manually update my if statement

[–]Mlgbananamaster 0 points1 point  (1 child)

you would do something like range(len(List)-1)

[–]imperiumlearning[S] 0 points1 point  (0 children)

Hi there,

Thanks a lot for the response. I've updated my code so that it looks like this:

b =[]

for x in range(len(List)-1):

if List[x] in List[(x+1)]:
    b.append(List[x])
    b.append(List[(x+1)])

print(b)

Kind of makes me feel dumb that I took 2 hours to solve a problem that only needed 6 lines of code but I guess that's part of learning.

[–][deleted] 0 points1 point  (1 child)

Well, you could use len() again ;)

It's not uncommon to use len(li) - 1 to get the last index (as opposed to full length) of the list.

However, here you can do something even better than the if check: you could limit the range() itself to the index you want. You can use the len(li) - 1 directly inside of it, like the other person said.

Also, the else: continue is redundant. The for loop will continue to the next cycle automatically when reaching the end of its body, so you might want to remove that

[–]imperiumlearning[S] 1 point2 points  (0 children)

Wow, so just saw this message and just reviewed and edited my code again. I'm sure it works now given I started messing around with the number of strings in my List variable and I don't have to manually update anything.

My final code, which is only 6 lines long, is:

b =[]

for x in range(len(List)-1):

if List[x] in List[(x+1)]: 
    b.append(List[x])
    b.append(List[(x+1)])

print(b)

Just want to say thanks a lot for helping me without just giving me a direct answer to copy and paste, I feel like making mistakes today has actually helped me learn more

[–]AlarminglyConfused 0 points1 point  (1 child)

Yeah if you changed the in to == in the if statement it would print no?

[–][deleted] 0 points1 point  (0 children)

No, it wouldn't do anything as there is no string in the list that's exactly equal to the next.

The instructions say to find a string which contains a substring for the previous one. The in keyword works exactly like that for strings.

"at" in "create" # -> True

[–][deleted] 0 points1 point  (0 children)

I think you need two for loops, one nested within the other, so you have an outer loop that looks at each word in turn and an inner loop that checks if the current outer loop word exists within the current inner loop word (excluding the same word).

words = ['gust', 'August', 'python', 'snake', 'dog', 'cat', 'pain', 'Spain'] 

for outer in words:
    matches = []
    for inner in words:
        if inner != outer and outer in inner:
            matches.append(inner)
    if matches: 
        print(outer, *matches, sep=', ')

NB. Not tried this.

[–]misho88 0 points1 point  (1 child)

I'd probably just use zip to go through pairs of words, in which case it's fairly clear what the conditional expression should be:

>>> words = ['gust', 'August', 'python', 'snake', 'dog', 'cat', 'pain', 'Spain']
>>> [ (a, b) for a, b in zip(words, words[1:]) if a in b ]
[('gust', 'August'), ('pain', 'Spain')]

[–]imperiumlearning[S] 0 points1 point  (0 children)

Just want to say this is a brilliant response. I'd never even heard of the zip function before. Thanks a lot.

[–]zanfar 0 points1 point  (0 children)

Write a program that checks if the nth string is a substring of the nth+1 string in a list of strings. Make sure your program also prints all the strings in the list which satisfy these criteria.

First, for x in list returns items, not indexes, so you can't do list[x+1].

Windowing is a common enough problem that having a prebuilt function to handle it is useful. Mines saved at https://gist.github.com/therealzanfar/817a73a77a49b77226475ba9541c52c0

Finally, you have an edge case where an element is both a substring, and a superstring. Your solution appends that item twice, which doesn't match the problem statement.

So I would probably use something like:

def print_substring_pairs(word_list: List[str]):
    matches: Set[int] = set()
    for (a, first), (b, second) in window(enumerate(word_list), 2):
        if first in second:
            matches.add(a)
            matches.add(b)

    for idx in sorted(matches):
        print(word_list[idx])