DEV Community

loading...

Daily Challenge #243 - Redacted!

thepracticaldev profile image dev.to staff ・1 min read

The first document has parts redacted, and the other one doesn't. But the clean document might be a fake! You need to compare the two documents and decide if it is possible they are the same or not. Return true if the two documents are possibly the same. Return false otherwise.

Rules

  • Each document is made of any visible characters, spaces, punctuation, and newlines \n
  • Any character might be redacted (except \n)
  • The redaction character is X
  • The redacted document is always the first one

Example

doc1 = "TOP SECRET:\nThe missile launch code for Sunday XXXXXXXXXX is:\nXXXXXXXXXXXXXXXXX"
doc2 = "TOP SECRET:\nThe missile launch code for Sunday 5th August is:\n7-ZERO-8X-ALPHA-1"
Documents look the same, therefore true.

Tests

doc1 = "The name of the mole is Professor XXXXX"
doc2 = "The name of the mole is Professor Dinglemouse"

doc1 = "XXXXXXXX XXXXXXX XXXXXXXXXXXXXXXXXXX\nXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX XXXXXXXXXXXXX XXXXX"
doc2 = "Area-51. Medical Report. 23/Oct/1969\nE.T. subject 4 was given an asprin after reporting sick for duty today"

Good luck!


This challenge comes from dinglemouse 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 (7)

pic
Editor guide
Collapse
qm3ster profile image
Mihail Malo • Edited

Rust

Assuming that replacement with X is per character.

fn same(bad: &str, real: &str) -> bool {
    bad.len() == real.len()
        && bad
            .chars()
            .zip(real.chars())
            .all(|(b, r)| b == r || (b == 'X' && r != '\n'))
}

yay, a oneliner

With nightly feature

#![feature(iter_order_by)]
fn same(bad: &str, real: &str) -> bool {
    bad.len() == real.len()
        && bad
            .chars()
            .eq_by(real.chars(), |b, r| b == r || (b == 'X' && r != '\n'))
}

When you're a caveman and reimplement all:

fn same(bad: &str, real: &str) -> bool {
    if bad.len() != real.len() {
        return false;
    }
    for (b, r) in bad.chars().zip(real.chars()) {
        if b != r && (b != 'X' || r == '\n') {
            return false;
        }
    }
    true
}

When you're a caveman and reimplement .zip()

fn same(bad: &str, real: &str) -> bool {
    if bad.len() != real.len() {
        return false;
    }
    let mut bad = bad.chars();
    let mut real = real.chars();
    while let (Some(b), Some(r)) = (bad.next(), real.next()) {
        if b != r && (b != 'X' || r == '\n') {
            return false;
        }
    }
    true
}

(none of the latter ones give better performance, only worse)

Collapse
vidit1999 profile image
Vidit Sarkar • Edited

Here is a C++ solution,

bool areSame(string doc1, string doc2){
    if(doc1.length() != doc2.length())
        return false;

    for(int i=0; i<doc1.length(); i++)
        if(doc1[i] != doc2[i] && (doc1[i] != 'X' || (doc1[i] == 'X' && doc2[i] == '\n')))
            return false;

    return true;
}
Collapse
mellen profile image
Matt Ellen

A javascript way. Although I think this could be done with regex...

function check(doc1, doc2)
{
  let docCheck = [...doc1].reduce((acc, cha, i) => 
  {
    if(cha.toLowerCase() === 'x')
    {
      acc += doc2[i];
    }
    else
    {
      acc += cha;
    }
    return acc;
  }, '');

  return docCheck === doc2;
}
Collapse
dimaip profile image
Dmitri Pisarev πŸ‡·πŸ‡Ί

This one can be slightly optimised to return early on failure and not go through the whole string:

const isSame = (a, b) => a.split('').every((char, index) => char === 'X' || char === b[index])
Collapse
mxb profile image
mxb

Implementation in Frink

same[redacted, original] :=
{
  Xval = char["X"]
  for x = zip[stringToBytes[redacted],stringToBytes[original]]
    if (x@0 != x@1) and (x@0 != Xval)
      return false
  return true
}
Collapse
exts profile image
Lamonte • Edited

Dart, bit longer, but it's fine lol. I still abide by the rule that not everything needs to be creative. Readability is my philosophy. If you can read the code and understand what's happening, the better for everything reading the code. Personally.

void main() {
  var doc1 = "TOP SECRET:\nThe missile launch code for Sunday XXXXXXXXXX is:\nXXXXXXXXXXXXXXXXX";
  var doc2 = "TOP SECRET:\nThe missile launch code for Sunday 5th August is:\n7-ZERO-8X-ALPHA-1";
  print(allegedlySimilar(doc1, doc2)); // true

  doc1 = "The name of the mole is Professor XXXXX";
  doc2 = "The name of the mole is Professor Dinglemouse";
  print(allegedlySimilar(doc1, doc2));  // false

  doc1 = "XXXXXXXX XXXXXXX XXXXXXXXXXXXXXXXXXX\nXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX XXXXXXXXXXXXX XXXXX";
  doc2 = "Area-51. Medical Report. 23/Oct/1969\nE.T. subject 4 was given an asprin after reporting sick for duty today";
  print(allegedlySimilar(doc1, doc2)); // true
}

bool allegedlySimilar(String doc1, String doc2) {
  var redacted = (data) {
    List<String> joined = List<String>();
    var lines = data.split("\n");
    for(var line in lines) {
      var data = StringBuffer();
      line.split('').forEach((char) => data.write('X'));
      joined.add(data.toString());
    }
    return joined.join("\n");
  };
  return redacted(doc1) == redacted(doc2);
}
Collapse
agtoever profile image
agtoever

Python 3, using regex'es:

# Solution
import re
match = lambda doc1, doc2: re.match(re.sub('X+', '.*?', doc1), doc2) is not None

# Test cases
cases = [
    ("TOP SECRET:\nThe missile launch code for Sunday XXXXXXXXXX is:\nXXXXXXXXXXXXXXXXX","TOP SECRET:\nThe missile launch code for Sunday 5th August is:\n7-ZERO-8X-ALPHA-1"),
    ("The name of the mole is Professor XXXXX", "The name of the mole is Professor Dinglemouse"),
    ("XXXXXXXX XXXXXXX XXXXXXXXXXXXXXXXXXX\nXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXX XXXXXXXXXXXXX XXXXX", "Area-51. Medical Report. 23/Oct/1969\nE.T. subject 4 was given an asprin after reporting sick for duty today")]

for case in cases:
    print(f"doc1: {re.sub('X+', '*', case[0])}\ndoc2: {case[1]}\nDoc's match: {match(*case)}")

Try it online!