DEV Community

loading...

Daily Challenge #244 - Search for Letters

thepracticaldev profile image dev.to staff ・1 min read

Create a function which accepts one arbitrary string as an argument, and return a string of length 26. The objective is to set each of the 26 characters of the output string to either '1' or '0' based on the fact whether the Nth letter of the alphabet is present in the input (independent of its case).

So if an 'a' or an 'A' appears anywhere in the input string (any number of times), set the first character of the output string to '1', otherwise to '0'. if 'b' or 'B' appears in the string, set the second character to '1', and so on for the rest of the alphabet.

For instance:
"a **& cZ" => "10100000000000000000000001"
'Abc e $$ z' => "11101000000000000000000001"

Tests

change("!!a$%&RgTT")
change("")
change("abcdefghijklmnopqrstuvwxyz")
change("aaaaaaaaaaa")

Good luck!


This challenge comes from Roy Gardiner on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Discussion (12)

Collapse
qm3ster profile image
Mihail Malo • Edited

Rust

yay fun with bitsets

fn change(hay: &str) -> String {
    let mut output = 0u32;
    for c in hay.chars() {
        match c {
            'a'..='z' => output |= 1u32 << (b'z' - c as u8),
            'A'..='Z' => output |= 1u32 << (b'Z' - c as u8),
            _ => {}
        }
    }
    format!("{:026b}", output)
}

// "Test"

fn main() {
    assert_eq!(change("a **& cZ"), "10100000000000000000000001");
    assert_eq!(change("Abc e $$ z"), "11101000000000000000000001");

    let c = |x| println!(r#"{} <= "{}""#, change(x), x);
    // "Tests"
    c("!!a$%&RgTT");
    c("");
    c("abcdefghijklmnopqrstuvwxyz");
    c("aaaaaaaaaaa");
}

On infinitely long strings it would be good to:

  1. Shrink the range when high or low characters already matched
  2. Return early if we achieve 0b11111111111111111111111111

but on such short strings these would both be slower

Edit:

I have stolen the ascii case sensitivity bit from @miketalbot and will now proceed to pleasure myself with this fish

fn change(hay: &str) -> String {
    let mut output = 0u32;
    for c in hay.chars() {
        if let c @ b'A'..=b'Z' = c as u8 & 0b11011111 {
            output |= 1u32 << (b'Z' - c)
        }
    }
    format!("{:026b}", output)
}

Is this actually faster?
No idea.
Alternatively

if let c @ b'A'..=b'Z' | c @ b'a'..=b'z' = c as u8 {
    output |= 1u32 << (b'Z' - (c & 0b11011111))
}

or even just

if matches!(c, 'A'..='Z' | 'a'..='z') {
    output |= 1u32 << (b'Z' - (c as u8 & 0b11011111))
}

🤷

Collapse
vidit1999 profile image
Vidit Sarkar • Edited

Here is a C++ solution,

string change(string s){
    string st(26, '0');

    for(char c : s)
        if(islower(c) || isupper(c))
            st[tolower(c)-'a'] = '1';

    return st;
}
Collapse
agtoever profile image
agtoever • Edited

Python 3.7

# solution
import string
change = lambda s: "".join(['1' if c in s.lower() else '0' for c in string.ascii_lowercase])

# testcases
for case in ["!!a$%&RgTT", "", "abcdefghijklmnopqrstuvwxyz", "aaaaaaaaaaa"]:
    print(f"change({case}) = {change(case)}")

Try it online!

(Sorry. I didn’t manage for format the code in markdown properly on my iphone)

Collapse
peritract profile image
Dan Keefe

I had roughly the same idea:

def isin(text):
  text = text.lower()
  return "".join([str(1)
                  if letter in text
                  else str(0)
                  for letter in "abcdefghhijklmnopqrstuvwxyz"])
Collapse
miketalbot profile image
Mike Talbot • Edited

This is a one statement in JS that works:

    (input)=>input.match(/[a-zA-Z]/g)
        .reduce((c,a)=>(c[(a.charCodeAt(0) & 31) -1]='1',c), 
           Array.from('0'.repeat(26)))
       .join('')
Collapse
capecodconnor profile image
connormaher92 • Edited

Here is a Ruby solution

def change(str)
  result = '0' * 26
  str = str.downcase
  str.each_char do |char|
    result[(char.ord - 97)] = '1' if char.ord.between?(97, 122)
  end
  result
end
Collapse
citizen428 profile image
Michael Kohl

Ruby can also multiply strings by numbers, which is a bit easier than joining an array:

'0' * 26
#=> "00000000000000000000000000"
Collapse
capecodconnor profile image
connormaher92

Thanks Michael, I like that better.

Collapse
peter279k profile image
peter279k

Here is the Python solution:

def change(st):
    answer_string = [
        '0','0','0','0','0','0','0','0','0','0','0','0','0',
        '0','0','0','0','0','0','0','0','0','0','0','0','0',
    ]

    upper_alphabets = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

    for char in st:
        upper_index = 0
        for upper_alphabet in upper_alphabets:
            if upper_alphabet == char or upper_alphabet.lower() == char:
                answer_string[upper_index] = '1'
            upper_index += 1

    return "".join(answer_string)
Collapse
mattymaloney profile image
mattymaloney • Edited
const countEm = (str) => {
  str = str.toLowerCase();
  return 'abcdefghijklmnopqrstuvwxyz'.split('').map((letter) => {
    return str.indexOf(letter) === -1 ? '0' : '1';
  }).join('')
};

Thanks for the challenge!

Collapse
qm3ster profile image
Mihail Malo

There's also String.prototype.includes

const letters = "abcdefghijklmnopqrstuvwxyz".split("")
const countEm = str => {
  str = str.toLowerCase()
  return letters.map(letter => str.includes(letter) ? "0" : "1").join("")
}
Collapse
iamhrithikraj profile image
Hrithik Raj • Edited

C++17


#include<bits/stdc++.h>
using namespace std;
int main() {
    string str;
    vector<int>vec(26, 0);
    getline(cin, str);
    transform(str.begin(), str.end(), str.begin(), ::tolower);
    for (auto i = str.begin(); i != str.end(); ++i) {
        if (isalpha(*i)) {
            vec[*i - 'a'] = 1;
        }
    }
    for (auto i = vec.begin(); i != vec.end(); ++i) {
        cout << *i;
    }

}
Forem Open with the Forem app