1

Hey I'm trying to create a function that takes in a string and a letter as arguments, identifies if there are two of this letter within the string, and then returns the number of characters between the two plus the letters. So 'Saturday' and 'a' would return 6.

def sublength(string, char):
    new_string = ''
    for i in string:
        if i == char:
            new_string.append(i)
            if i != char:
                new_string.append(i)
                if i == char:
                    new_string.append(i)
                    break
    return len(new_string)
            

What I want to do is iterate through string until char is found, add this character to new_string, continue to iterate and add the subsequent characters until char is found again, add it and then stop. This would be done in one iteration. However, as it's currently constructed, my function iterates through all of the string looking for matches and then stops. How do I either do this in one iteration or break up the string to achieve the same functionality? Thanks!

If you can provide a solution in JS as well I would really appreciate it!!

Wiseface
  • 183
  • 2
  • 11
  • do you want the first repeated letter or the largest repeated gap? – Paul Brennan Nov 18 '20 at 22:13
  • You can keep indexes of first and second occurrence of char 'c'. Currently, when you are appending then you are recreating string. By design string are immutable. So, its better to slice them once by having indexes. – Ajay Nov 18 '20 at 22:17
  • I want the character count between and including the two common characters. So in my example of 'Saturday' and 'a' the answer would be 6: a-1, t-2, u-3, r-4, d-5, a-6. I want to do this without RegEx. – Wiseface Nov 18 '20 at 22:17
  • Alternatively, you can play with regex to achieve the same. – Ajay Nov 18 '20 at 22:18
  • What should 'banana' and sep 'a' return? – wim Nov 18 '20 at 23:06
  • 1
    I'm only interested in strings that contain char twice so 'banana' and 'a' should return 0 – Wiseface Nov 18 '20 at 23:14
  • Should 'banana' and 'c' also return 0? What about 'banana' and 'b'? – wim Nov 18 '20 at 23:37
  • 1
    Any string that doesn't have char * 2 should return 0 – Wiseface Nov 18 '20 at 23:52

8 Answers8

4

Little known fact, str.index accepts a second argument for where to begin searching from:

>>> s = "Saturday"
>>> first = s.index("a")
>>> second = s.index("a", first + 1)
>>> second - first + 1
6

This is more efficient than string[start+1:].index(char) because that way makes an unnecessary copy.

Putting it into a function:

def sublength(string, char):
    if string.count(char) != 2:
        return 0
    first = string.index(char)
    second = string.index(char, first + 1)
    return second - first + 1

Returns 0 if char is not present exactly twice within string.

wim
  • 338,267
  • 99
  • 616
  • 750
  • Yeah. To add it accepts third argument as end index till where to search. – Ajay Nov 18 '20 at 22:32
  • Also, wrap this under a try catch to avoid edge case errors. – Ajay Nov 18 '20 at 22:34
  • Hmm...I actually might agree with your second point. In fact, I like it better than the extra walk over the string to check for two characters. But it's fine. As to the first point, it's a matter of quality of the answer. It's hard for someone to copy/paste your answer to try it or to use it, for instance. - Your second version is good. Got my up vote. – CryptoFool Nov 18 '20 at 23:45
  • @Steve Unfortunately the check for exactly 2 characters is necessary, OP said *I'm only interested in strings that contain char twice so 'banana' and 'a' should return 0*. – wim Nov 18 '20 at 23:50
  • Ah! I didn't see the late comments. Cool. – CryptoFool Nov 18 '20 at 23:51
0

Shortcut method:

try:
    print(string[string.index(char)+1:].index(char)+2)
except:
    print(char ,'is not present twice in ', string)

OR

pos = string[string.find(char)+1:].find(char)+2
if pos == 1 :
    print(char ,'is not present twice in ', string)
else:
    print("Are present at a distance of",pos)
Shadowcoder
  • 962
  • 1
  • 6
  • 18
0

I would solve this by using regex. But to follow your try, see whats wrong when you see a solution next to your try.

def sublength(string, char):
new_string = ''
found = False
for i in string:
    if i == char:
        if not found:
            new_string += i
            found = True
        else:
            new_string += i
            found = False
            break
    elif found:
        new_string += i
if found:
    new_string = ""
return len(new_string)

But keep in mind, there is no check for upper and lower case ...

Update: Here the solution with Regex

import re
if re.search("a.*?a", "Saturday"):
    print(len(re.search("a.*?a", "Saturday").group(0)))
else:
    print("Nope")
Detman
  • 3
  • 3
  • Your second solution is kinda cool, although it's too bad you have to do the matching twice. If you stored away the match first, and then used it twice, you could avoid that. – CryptoFool Nov 18 '20 at 22:53
0

Just out of curiosity, an approach using regex:

import re

def substring_length(string, char):
    match = re.search(f'{char}.+{char}', string)
    match_length = len(match.group(0)) if match else 0
    return match_length

Some tests:

# Returns the expected results when there are two target characters
print(substring_length('Saturday', 'a'))
6

# Returns 0 when there aren't at least two target characters
print(substring_length('Saturday', 'z'))
0

# When there are more than two target characters, calculate the length from the start matching character to the last matching character
print(substring_length('Researcher', 'e'))
8
Cainã Max Couto-Silva
  • 4,839
  • 1
  • 11
  • 35
0
def f(s, c):
    s = s.lower()
    if s.count(c) != 2:
        return 0
    return s.index(c, mn+1)-s.index(c)+1
    

f('Saturday', 'a')
Vinay Emmaadii
  • 125
  • 1
  • 11
0

In JavaScript, you could do it this way:

function subLength(word, character) {
  const regexString = `[${character}]`;
  const regex = new RegExp(regexString, 'g');
  const found = word.match(regex);
  
  if (found.length !== 2) {
    return 0;
  } 
  
  first = word.indexOf(character);
  second = word.lastIndexOf(character);
  
  return second - first + 1;
};

subLength('Saturday', 'a'); // returns 6
-1

You can use string.index() method to ease your situation:

def sublength(string, char):
    try:
        start = string.index(char)
        end = string.index(char, start+1)
    except: return 'No two instances'
    else: return end +2

index() will return the position of character in the string. You can use it to find indices and number of characters between them.

How does this works?

  1. start finds first occurrence of character
  2. end finds first occurance of character AFTER the index at which start is discovered (thats why indexing from start+1 so to search string from after the first occurance till end. Because thats where we need to search for second occurenece)
  3. if both indices are found, it goes on to else to return difference Plus 2 as it is counting both elements (mere difference return number of characters between them excluding both)
  4. if both arent found it returns string : 'No two instances'

P.S. returns 6 for sublength('Saturday', 'a') i.e. works as intended and is one-go!

Hamza
  • 5,373
  • 3
  • 28
  • 43
  • This is great! can you explain the end variable and return statement? Thanks! – Wiseface Nov 18 '20 at 22:27
  • `index` takes a starting position. No need to slice the target string – CryptoFool Nov 18 '20 at 22:27
  • Its fixed now! No need to add start again as it is incorporating that in end logic – Hamza Nov 18 '20 at 23:15
  • That `index` takes a starting position is exactly why it isn't necessary to slice the string. Just have it start looking at 1 past the first match the second time. (see @wim's answer...no slice...no problem) – CryptoFool Nov 18 '20 at 23:50
-1

Little long solution:-

public static int getCharBetween(String s, char c){
        if(s.equals(null) ||s.length()==0){
            return -1;
        }
        char[] ch=s.toCharArray();
        List<Integer> list= new ArrayList<>();
        for(char cha:ch){
            if(cha==c){
                list.add(s.indexOf(cha));
                s=s.substring(s.indexOf(cha)+1, s.length()-1);
                if(list.size()==2){
                    break;
                }
            }
        }
        if(list.size()==0){
            return -1;
        }
        return (list.get(1)-list.get(0))-1;
}
Parikshit
  • 1
  • 1