DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #244 - Search for Letters

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!

Top comments (11)

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;
    }

}
Enter fullscreen mode Exit fullscreen mode
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
 
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
 
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
 
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
 
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
 
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
 
capecodconnor profile image
connormaher92

Thanks Michael, I like that better.