DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #259 - Duplicate Encoder

The goal of this exercise is to convert a string to a new string where each character in the new string is "(" if that character appears only once in the original string, or ")" if that character appears more than once in the original string. Ignore capitalization when determining if a character is a duplicate.

Examples
"Success" => ")())())"
"(( @" => "))(("

Tests
"din"
"recede"

Good luck!


This challenge comes from obnounce 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!

Latest comments (27)

Collapse
 
moufeed_m profile image
Mofid Jobakji • Edited
const encoder = str =>
  str
    .toLowerCase()
    .replace(/\W|\w/g, (chr) =>
      str.indexOf(chr) === str.lastIndexOf(chr) ? '(' : ')'
    );
Collapse
 
quoll profile image
Paula Gearon • Edited

Clojure

(defn duplicate-encode
  [s]
  (let [s (clojure.string/lower-case s)
        f (frequencies s)]
    (apply str (map #(if (= 1 (f %)) \( \)) s))))
Collapse
 
jessekphillips profile image
Jesse Phillips • Edited

I'm a little late, but rather than solving the problem I instead took the different approaches people posted, wrote them in D (dlang.org) and did some basic performance ploting.

GitHub logo JesseKPhillips / devto-challenge259-dupencoder

An attempt to capture performance with different implementation approaches for a Challenge

Dev.to has a daily challenge and I happened upon the Duplicate Encoder #259 for 2020

I didn't really want to solve the challenge per se, so instead I took the top comments for implementation and wrote them in D Lang.

For clarity these are all implemented in D and do not reflect the language performance that the implementation is based on.

Image of Yaktocat

The "Haskel" implementation utilizes a range based map/filter approach to detecting duplicates.

The "PHP" implementation utilizes a nested loop apporach to intentify that the character occurs again.

The "Pointer" implementation was just something I wanted to try. It duplicates the array so it is mutable after which point it does not loop over the arry twice and instead stores pointers to the location of the same character. It takes quite a bit for this approach to see any performance gain.




I might do more work on this and write up my own post about what I did. Keep in mind that I use the terms 'php' and 'haskel' not to indicate the performance of those languages... it was just the language utilized for the approach taken. All timings are from D.

Collapse
 
arthelon profile image
Arthelon

TypeScript:

function isUnique(char: string, fullString: string): boolean {
  return fullString.indexOf(char) === fullString.lastIndexOf(char);
}

function duplicateEncoder(input: string): string {
  const lowercase = input.toLowerCase();
  return lowercase
    .split("")
    .map((char) => (isUnique(char, input) ? "(" : ")"))
    .join("");
}

Collapse
 
elcio profile image
Elcio Ferreira

A magical Python solution:

def encode(text):
    return ''.join((')' if text.lower().count(c.lower()) > 1 else '(' for c in text))

A boring Python solution:

def encode(text):
    encoded = ''
    for char in text:
        encoded += replace_char(char, text)
    return encoded

def replace_char(char, text):
    if text.lower().count(char.lower()) > 1:
        return ')' 
    return '('

Boring is good. I usually avoid oneliners and magical solutions.

A more "production ready" version of the above:

'''A "duplicate encoder"s.

Based on https://dev.to/thepracticaldev/daily-challenge-259-duplicate-encoder-2e8l

When running on command line, encodes standard input.

You can also use the following args:

-t : Executes automated testing
-h : Shows this help'''

def encode(text):
    '''Convert a string to a new string where each character in the new string
    is "(" if that character appears only once in the original string, or ")"
    if that character appears more than once in the original string.
    Examples:
    >>> encode('Success')
    ')())())'
    >>> encode('(( @')
    '))(('
    >>> encode('din')
    '((('
    >>> encode('recede')
    '()()()'
    '''
    encoded = ''
    for char in text:
        encoded += replace_char(char, text)
    return encoded

def replace_char(char, text):
    '''Returns ')' if char appears more than once in text. Otherwise, 
    returns '('. Case insensitive. Examples:
    >>> replace_char('a', 'banana')
    ')'
    >>> replace_char('B', 'banana')
    '('
    '''
    if text.lower().count(char.lower()) > 1:
        return ')'
    return '('

if __name__ == '__main__':
    import sys
    if sys.argv[-1] == '-t':
        import doctest
        doctest.testmod()
    elif sys.argv[-1] == '-h':
        import pydoc
        print(pydoc.getdoc(sys.modules[__name__]))
    else:
        print(encode(sys.stdin.read()))
Collapse
 
ilhotiger profile image
Ilho Song

Erlang solution, though not sure this would be the most efficient. I am still learning the language :)

process(Input) ->
    ResultMap = lists:foldl(
        fun(Char, Map) -> 
            case maps:is_key(Char, Map) of
                true -> maps:put(Char, ")", Map);
                false -> maps:put(Char, "(", Map)
            end
        end, 
        maps:new(), 
        string:lowercase(Input)),
    lists:foldl(
        fun(Char, Acc) -> lists:append(Acc, maps:get(Char, ResultMap)) end,
        "",
        string:lowercase(Input)
    ).
Collapse
 
lexlohr profile image
Alex Lohr

Rust 🦀🦀🦀🦀solution:🦀🦀🦀🦀🦀 🦀

fn encode_duplicate_characters(text: &str) -> String {
    let text = text.to_lowercase();
    text.chars().map(|c| if text.matches(c).count() == 1 { '(' } else { ')' }).collect()
}
Collapse
 
gnunicorn profile image
Benjamin Kampmann

In Rust – playground link (with tests)

pub fn dub_enc(inp: String) -> String {
    let lowered = inp.to_lowercase();
    lowered
        .chars()
        .map(|c| {
            let mut finder = lowered.chars().filter(|r| *r == c);
            finder.next(); // exists
            if finder.next().is_some() { // found at least once more
                ")"
            } else {
                "("
            }
        })
        .collect()
} 
Collapse
 
lexlohr profile image
Alex Lohr

Why not use std::str::matches to iterate over the same chars?

Collapse
 
gnunicorn profile image
Benjamin Kampmann

I suppose that is a valid alternative. Just not the first thing that came to mind ...

Thread Thread
 
lexlohr profile image
Alex Lohr

I just love how Rust has a helpful method for about everything in its std/core libs.

Collapse
 
patricktingen profile image
Patrick Tingen • Edited
/* Progress 4GL Daily Challenge #259
*/
FUNCTION dupDecode RETURNS CHARACTER (pcString AS CHARACTER):
  DEFINE VARIABLE i AS INTEGER NO-UNDO.
  DO i = 1 TO LENGTH(pcString):
    pcString = REPLACE( pcString
                      , SUBSTRING(pcString,i,1)
                      , STRING(NUM-ENTRIES(pcString,SUBSTRING(pcString,i,1)) = 2,'(/)')
                      ).
  END.
  RETURN pcString.
END FUNCTION.

MESSAGE dupDecode('Success')
  VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
Collapse
 
jingxue profile image
Jing Xue • Edited

Python:



from collections import Counter


def duplicate_encoder(s: str) -> str:
    all_lower = s.lower()
    counter = Counter(all_lower)
    return ''.join([')' if counter.get(c) > 1 else '(' for c in all_lower])