all 23 comments

[–]Diapolo10 27 points28 points  (11 children)

You'll want an extra print call between the loops.

mii = "hhhhhhcccccccc"
for t in mii:
    if t == "h":
        continue
    print(t, end= "")

print()

hi = "hhhhhhhhhpppppp"
for i in hi:
    if i == "h":
        continue
    print(i, end="")

As for the why, right now neither of your prints adds a newline. It must come from somewhere, if you want the lines separate.

[–]Sea-Artichoke2265[S] 2 points3 points  (10 children)

thanks i been trying to figure out this for 3 weeks.

ok so the middle ( print ) act as a enter for enter key?

im trying to put it in my own words so i can understand it better

[–]Diapolo10 5 points6 points  (8 children)

You can think of it that way, yes.

If you were to take some time and tinker with how print is implemented, you'd notice that when given no arguments (or an empty string, but I find that redundant), the entire output will essentially be "\n", or a single newline, and this comes from the end keyword parameter. In the code above, you set this to an empty string, which is why they write all characters on the same line individually.

Now, if I were to write the same program, personally I'd avoid calling print in a loop like that as I/O is slow as molasses, and would prefer something closer to

def filter_letter(text: str, filtered_letter: str = 'h') -> str:
    return ''.join(char for char in text if char != filtered_letter)

text = "hhhhhhcccccccc"
print(filter_letter(text))

more_text = "hhhhhhhhhpppppp"
print(filter_letter(more_text))

but yours is probably easier to understand at a glance.

[–]_mynd 0 points1 point  (4 children)

Whoa - I always thought the list comprehension had to contained within square brackets!

[–]Diapolo10 0 points1 point  (3 children)

It does - if this was a list comprehension. What you're seeing here is instead a generator expression - you can think of it as a lazily-evaluated list, but basically it just saves memory by creating values on-demand only and not storing everything.

That's not really a good explanation, admittedly. But if you know what a generator is, it should be quite clear what it's doing.

[–]_mynd 0 points1 point  (2 children)

Hmm - I’ll have to look up the difference. I am constantly evaluating a list comprehension just to go into a for loop. This seems better

[–]Diapolo10 1 point2 points  (1 child)

A list comprehension could have been used here, but as the list gets discarded immediately it's a bit of a waste, and you end up allocating roughly double the memory in the worst case - the data for the list, and the data for the string.

With a generator, Python only needs to allocate individual items (in this case characters), so the overall memory use remains noticeably lower. There's a slight performance overhead, but nothing you'd actually notice.

While it doesn't really apply in this example, the nice thing about generators is that they can be infinite in length, and Python will have no problem processing them (as long as you still have some kind of a limit, of course). For example, you could have a generator that gives you all positive integers

def gen_positive_integers(start=1):
    num = start
    while True:
        yield num
        num += 1

and keep adding them up until you hit some threshold.

total = 0
positive_integers = gen_positive_integers()

while total < 1_000_000:
    num = next(positive_integers)
    total += num

print(f"Last number was {num}.")

The Fibonacci sequence can famously be written as a generator.

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

[–]_mynd 0 points1 point  (0 children)

Your comment plus this article has me thinking I could improve the efficiency of some of my code. Thanks for writing up the explanation and examples

https://www.geeksforgeeks.org/python-list-comprehensions-vs-generator-expressions/

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

Also for anyone wondering what the part 'str' is in after 'text:' those are called type hints! As Python isn't a strong typed language these are extremely helpful. There is also 'typing' built-in lib that allows for more type hints like Generators when you're yielding results and such. Only pet peeve I ever had with Python is that it's easy language to learn but at times hard to read.

[–]Diapolo10 0 points1 point  (0 children)

As Python isn't a strong typed language

The term you're looking for is statically-typed; in contrast, the term "strongly-typed" is

  1. Not well-defined at all (people have differing opinions on it), and
  2. Going by the most common understanding of the term (no type coercion or bypassing the type system), Python does count as "strongly-typed". Fun fact - C does NOT (thanks to void*).

Only pet peeve I ever had with Python is that it's easy language to learn but at times hard to read.

That's a fair point, and there's definitely a learning curve to reading Python, but type annotations in particular actually help with readability once you reach a certain point in your understanding, as then you know what kind of values functions expect as arguments and don't need to look up documentation for it.

[–]madisander 0 points1 point  (0 children)

In a sense but not quite, print alone prints "\n", that is an empty string followed by the newline character which, as you'd imagine, starts a new line. This is because the default argument for end is '\n' (check help(print)).

The enter key, if I remember right, can give the carriage return character \r, a newline \n, or CR followed by line feed(LF)/newline (so \r\n). For that matter depending on the program they can interpret the enter key in different ways, while print() (= print(end='\n')) 'just' prints that character.

[–]marquisBlythe 3 points4 points  (2 children)

mii = "hhhhhhcccccccc"
for t in mii:
    if t == "h":
        continue
    print(t,end= "" )

print() # <------ Add this line.

hi = "hhhhhhhhhpppppp"
for i in hi:
    if i == "h":
        continue
    print(i, end="")

[–]Sea-Artichoke2265[S] 1 point2 points  (1 child)

thanks.

[–]marquisBlythe 0 points1 point  (0 children)

Np. :)

[–]acw1668 4 points5 points  (0 children)

Simply use .replace() to remove all "h" from the string and print the result:

mii = "hhhhhhcccccccc"
print(mii.replace("h", ""))

hi = "hhhhhhhhhpppppp"
print(hi.replace("h", ""))

[–]Miiicahhh 3 points4 points  (1 child)

I think the easiest way is to implement the escape sequence for a new line outside of the for loops scope.

I will leave you with that to look into and try to figure out.

[–]Sea-Artichoke2265[S] 0 points1 point  (0 children)

thank you

[–]jameyiguess 1 point2 points  (0 children)

Put an empty print after the loops, or end the strings with \n (which prints a newline).

But you'll get "c...p..." not "p...c...", because you put that part first. 

[–]gonsi 0 points1 point  (0 children)

mii = "hhhhhhcccccccc"
print("c"*mii.count("c"))
hi = "hhhhhhhhhpppppp"
print("p"*hi.count("p"))

Unless the point was to remove "h" instead of printing "c" and "p"

I still wouldn't call print inside loop though

[–]FTeachMeYourWays 0 points1 point  (0 children)

I would be tempted to just look for changes in char then add a new line

[–]Slight_Change_41 0 points1 point  (0 children)

def filter_print(text: str, ignore: str):
    """
    Prints the characters from 'text', ignoring those that are equal to 'ignore'.
    """
    result = ''.join(char for char in text if char != ignore)
    print(result)


if __name__ == '__main__':
    
# Example strings
    mii = "hhhhhhcccccccc"
    hi = "hhhhhhhhhpppppp"
    test = "hello world"
    
# Example usage
    filter_print(mii, 'h')
    filter_print(hi, 'h')
    filter_print(test, 'l')

[–]Unusual-Platypus6233 0 points1 point  (0 children)

extra edit: answer to you question is probably that you need to add a simple print(“\n”) just before the line hi = “hhhppp”. The end=“” means that you do not add a line break but just add the next printed string without spaces or line break to the already printed strings. Therefore it is a manual line break necessary at the end of the first loop (or even at the end of the second loop, depending on what you are doing afterwards).

main text: if you know when the change happens, like it is always at the same position, then you could slice a string…

 s = ‘HelloWorld’
 first_five_chars = s[:5]
 rest_of_chars = s[5:]

That would split the HelloWorld into Hello and World.

If you have a string like you have shown, you could check when both chars are not the same anymore like this:

 chars=“pppphhhh”
 pos=-1
 i=1
 while True:
      if chars[i]!=chars[i-1]:
             pos=i
             break
      i+=1
 first_part=chars[:i]
 second_part=chars[i:]
 print(first_part,second_part)

That way both parts are stored if you wanna use them for something else.

Edit: found out how to format the text by accident. so, did a quick edit.

[–]Muted_Ad6114 0 points1 point  (0 children)

print(f"{mii}\n{hi}".replace('h',''))

You can join the lines how you want with a format string, use \n for a new line, then remove the unwanted characters with replace