Check if specific characters are in the string

I need to find and count how many characters can be found in a string. I split the characters into chars1 [a: m] and chars2 [n: z] and had two counters.

The output should be 0/14, but instead it is 0/1. I think it only checks to see if it contains one and only one element, and then exits the loop. Is that the case?

Here is the code.

string_1 = "aaabbbbhaijjjm" def error_printer(s): chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" counter1 = 0 counter2 = 0 if ((c in s) for c in chars1): counter1 += 1 elif ((c in s) for c in chars2): counter2 += 1 print(str(counter2) + "/" + str(counter1)) error_printer(string_1) 
+5
source share
6 answers

The number of characters in chars1 / chars2 that occur in s

This makes sense as you grow with the if condition . Since if not in a loop, you can increment it once.

Now we can deploy the generator in a for loop . This will solve one part of the problem and generate 0/6 :

 for c in chars1: if c in s: counter1 += 1 for c in chars2: if c in s: counter2 += 1 

However, this still will not be terribly effective: in order to check if a character is in a string, O (n) worst case is required. You can first build a set with characters in a string, and then do a search (usually this is O (1) in the middle case:

 def error_printer(s): sset = set(s) chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" counter1 = 0 counter2 = 0 for c in chars1: if c in sset : counter1 += 1 for c in chars2: if c in sset : counter2 += 1 print(str(counter2) + "/" + str(counter1)) 

Now we have improved the efficiency, but still not very elegant: it takes a lot of code, and in addition, you need to check the code to know what it does. We can use the sum(..) construct to calculate the number of elements that satisfy a certain constraint, for example:

 def error_printer(s): sset = set(s) chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" counter1 = sum(c in sset for c in chars1) counter2 = sum(c in sset for c in chars2) print(str(counter2) + "/" + str(counter1)) 

This creates 0/6 , because in the range [AM] there are six characters in s and 0 in the range [NZ] that occur in s .

The number of characters in s that occur in char1 / char2

However, based on the main question, you want to count the number of characters in s that occur in two different ranges .

Another related issue is counting the number of characters encountered in char1 / char2 . In this case, we just need to swap the loops :

 def error_printer(s): chars1 = set( "abcdefghijklm" ) chars2 = set( "nopqrstuvwxyz" ) counter1 = sum(c in chars1 for c in s ) counter2 = sum(c in chars2 for c in s ) print(str(counter2) + "/" + str(counter1)) 

This creates 0/14 , since s has 14 characters that occur in the range [AM] (if 'a' occurs twice in s , then we count it twice) and none of the characters in s occur in the range [NZ] .

Using Range Checks

Since we work with ranges , we can use comparisons instead of element checks and run them with two comparisons, for example:

 def error_printer(s): counter1 = sum( 'a' <= c <= 'm' for c in s) counter2 = sum( 'n' <= c <= 'z' for c in s) print(str(counter2) + "/" + str(counter1)) 
+7
source

Try increasing with the if condition with one loop over s.

 for c in s: if c in char1: counter1 += 1 if c in char2: counter2 += 1 
+6
source

Alternative for for loops:

 string_1 = "aaabbbbhaijjjm" def error_printer(s): chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" counter1 = sum(s.count(c) for c in chars1) counter2 = sum(s.count(c) for c in chars2) print(str(counter2) + "/" + str(counter1)) error_printer(string_1) 

When you count how many times "a" , "b" , "c" ... are shown in the string input, you sum it up.

It is still inefficient, but uses the functions string.count and sum , which makes it a little easier to read and understand what is happening.

+4
source

One for looping over s for both counters:

 string_1 = "aaabbbbhaijjjm" def error_printer(s): chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" counter1 = 0 counter2 = 0 for c in s: if c in chars1: counter1 += 1 if c in chars2: counter2 += 1 print(str(counter2) + "/" + str(counter1)) error_printer(string_1) 
+2
source

You can use collections.Counter in combination with sum :

 from collections import Counter def error_printer(s): cnts = Counter(s) chars1 = "abcdefghijklm" chars2 = "nopqrstuvwxyz" print(sum(cnts[c] for c in chars2), '/', sum(cnts[c] for c in chars1)) >>> error_printer("aaabbbbhaijjjm") 0 / 14 
+2
source

As already mentioned, for loops - the way. You used the generator expression as a boolean for the if statement, which will be executed only once. The first expression was evaluated True , but this will not force it to run the enclosed code more than once. However, since the first if executed, elif never even evaluated its conditional value. That's why you want for loops, but you should not iterate over char1 and char2, you want to iterate over s:

 for c in s: if c in char1: counter1 += 1 if c in char2: counter2 += 1 print(str(counter2) + "/" + str(counter1)) 

This points to some simple ways to do this, first using c in charX as iterators:

 for c in s: counter1 += c in char1 counter2 += c in char2 

Now this is getting a little less clear, but we can make it even cleaner by adding a second loop:

 char = ['abcdefghijklm','nopqrstuvwxyz'] counter = [0,0] for c in s: for i in [0,1]: counter[i] += c in char[i] 

This is probably promoting it too much, but I hope this helps you understand how you can reorder these things in python!

(edit based on comments below)

+1
source

Source: https://habr.com/ru/post/1269726/


All Articles