Idontpaythe1
Idontpaythe1

Reputation: 1

code unable to distinguish between duplicate values in a list

I am a beginner learning python, trying to accomplish the following:

Given two strings of equal length, e.g:

string_1 = 'Hello' string_2 = 'World' print them vertically side by side, with a space between each character:

H W
e o
l r
l l
o d

however I am encountering an issue with my code where the first and second 'l' in 'Hello' are being treated as the same letter, which is leading to some issues in output

here is my code:

string1 = 'Hello'
string2 = 'World'
indx = ''

for letter in string1:
    indx = int(string1.index(letter))
    print(letter + ' ' + string2[indx])

it ends up giving the result as shown(area of concern bolded for easier viewing):

H W
e o
l **r**
l **r**
o d

instead of:

H W
e o
l **r**
l **l**
o d

My question is how I can modify the code such that it can distinguish between the 2 'l's in 'Hello', or if my code was entirely wrong to begin with. Am not sure how to proceed with this

As I am just starting out I am not sure how to deal with this issue and hope to get some advice on how to rectify the issue and improve the code.Thanks.

Upvotes: -1

Views: 78

Answers (3)

Adon Bilivit
Adon Bilivit

Reputation: 27316

As @Grismar has rightly pointed out, your code will not work if either of the strings have duplicated letters.

What you really want to do is iterate over the strings "side-by-side". The built-in zip function will work if both strings are of equal length. For strings of equal or differing lengths you could use itertools.zip_longest

Try this:

from itertools import zip_longest

string1 = 'Orange'
string2 = 'Grapefruit'

for p in zip_longest(string1, string2, fillvalue=" "):
    print(*p)

Output:

O G
r r
a a
n p
g e
e f
  r
  u
  i
  t

If, for some reason, you're not comfortable with zip_longest() then you could even write something that will handle an arbitrary number of strings.

Something like this:

from collections.abc import Iterator

def yc(s: str) -> Iterator[str]:
    yield from s
    while True:
        yield " "

def vprint(*s: str) -> None:
    gf = [yc(a) for a in s]
    for _ in range(max(map(len, s))):
        print(*(next(g) for g in gf))


vprint("Orange", "Grapefruit", "Tomato", "Banana", "Lemon")

Output:

O G T B L
r r o a e
a a m n m
n p a a o
g e t n n
e f o a  
  r      
  u      
  i      
  t      

Upvotes: 3

Grismar
Grismar

Reputation: 31396

You are using the position of the first occurrence of a letter in the first string to index the second string. However, since the letter appears twice, you get the same index every time you try. You stated "I want indx to take on the placement value of each letter?" which is fair, and there's several ways to achieve that.

For all those solutions though, you have to consider these scenarios:

  • string1 could be longer than string2

  • string1 could be shorter than string2

Here are some possible solutions:

  • For both strings, the index you want goes from 0 to the length of the strings; so you could literally for indx in range(0, len(string1)) like @johngordon's answer suggests
string1 = 'Hello'
string2 = 'World'

for idx in range(len(string1)):
    print(string1[idx], string2[idx])

This causes an error if string2 is shorter, and only prints the first letters from string2 if it is longer.

  • For each letter from string1, you want the accompanying index which can be done with enumerate():
string1 = 'Hello'
string2 = 'World'

for indx, letter in enumerate(string1):
    print(letter + ' ' + string2[indx])

This has the same behaviour - you get an error if string2 is shorter, and only the first first few letters matching string1's length if it is longer.

  • For each letter from string1, you can just get the next letters from string2 and keep track of it as you go:
string1 = 'Hello'
string2 = 'World'
indx = 0  # note that '' is not a very good value, since you need an integer, not a string

for letter in string1:
    print(letter + ' ' + string2[indx])
    indx += 1  # increase the index so that it has the right value for the next iteration

Again, the same problem.

  • Instead of dealing with the index, you can just use library functions like zip() to get a letter from each string pairwise:
string1 = 'Hello'
string2 = 'World'

for letter1, letter2 in zip(string1, string2):
    print(letter1 + ' ' + letter2)

This never causes an error, but you only get the number of characters that matches the shortest length, so you're not guaranteed to get all the letters from string1 if string2 is shorter.

If you always want all the letters from both strings, and blanks for the other, you could do something like:

string1 = 'Hello'
string2 = 'World'
longest = max(len(string1), len(string2))

for indx in range(longest):
    letter1 = ' ' if indx >= len(string1) else string1[indx]
    letter2 = ' ' if indx >= len(string2) else string2[indx]
    print(letter1 + ' ' + letter2)

By the way, shortening an already short name like index to indx is generally a bad idea. Pick a name that's descriptive and doesn't require someone to remember how you decided to spell it - index would be better. If you can't use index because something else already used that, consider putting your code in a separate function and call it. That makes the code more reusable (especially if you do a good job with nice function arguments) and organised.

Upvotes: -1

John Gordon
John Gordon

Reputation: 33351

In this case you probably want to iterate over the positions in the string, instead of the letters.

for idx in range(len(string1)):
    print(string1[idx], string2[idx])

Upvotes: 0

Related Questions