11
\$\begingroup\$

Objective

Write a program or function (or equivalent) that sorts out and returns the odd letter in the matrix of random size.

Details

You will be passed a matrix (as a string) as input of random dimensions such as this.

bbbbbbbbbb
bbbbbdbbbb
bbbbbbbbbb
bbbbbbbbbb
bbbbbbbbbb

Your job is to find the letter that doesn't match the rest (in this case, it is d, found at line 2, col 6) and to return that letter as output. The matrix will consist of letters A-Z, a-z, newlines (\n, only on ends of rows) and have dimensions ranging from 5x5 to 10x10 (25-100 letters).

Standard loopholes apply. This is a code golf challenge; entry with code of least bytes wins.

Input

Input will be passed in through standard input as a string if it is a program or as an argument if a function (or similar).

Output

A single character that is the "odd" in the matrix or None, nil, NUL, or the string "None" if there is no "odd" character.

More Examples

AAAAAAA
AAAAAAA
AAAAAAA
AAAIAAA
AAAAAAA

Answer: I

vvqvvvvvvv
vvvvvvvvvv
vvvvvvvvvv
vvvvvvvvvv
vvvvvvvvvv

Answer: q

puuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu
uuuuuuuuu

Answer: p

Generator

Here is a random matrix generator written in Python that you can use to test your program. Note: There is a slight chance that it could make a mistake and not put in an odd letter.

Instructions

1. Copy this code into a file called `matrix_gen.py`.
2. Run it with `python matrix_gen.py`.

---

from random import randint

rows = randint(5,10)
cols = randint(5,10)

charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
neg = charset[randint(0,51)]
pos = charset[randint(0,51)]
p_used = 0

comp = 0
matrix = ""

while comp < rows:
  row = ""
  while len(row) < cols:
    if not p_used and not randint(0,10):
      p_used = 1
      row = row + pos
    else:
      row = row + neg
  row = row + "\n"
  matrix = matrix + row
  comp += 1

print matrix[:-1]

\$\endgroup\$
  • 1
    \$\begingroup\$ Here is a literal translation of your Python code into JS. \$\endgroup\$ – Arnauld Nov 28 '17 at 10:09
  • 1
    \$\begingroup\$ @juniorRubyist "removing the bonus" isn't the same as "making the bonus mandatory". By moving the part that was optional so far into the requirements of the challenge, you've invalidated a large part of the existing answers. \$\endgroup\$ – Martin Ender Nov 30 '17 at 8:50

34 Answers 34

13
\$\begingroup\$

Python 3, 27 bytes

lambda x:min(x,key=x.count)

Try it online!

\$\endgroup\$
6
\$\begingroup\$

J, 12 10 7 bytes

-.}./.~

Try it online!

    /.~        Group identical items together
  }.           Remove one item from each group
-.             Remove the rest from the input

10 byte version

-._1 1{\:~

hisss...

       \:~        Sort down
  _1 1{           Take the last character (which is a newline) and the second one.
-.                Remove those from the input
\$\endgroup\$
  • 2
    \$\begingroup\$ @ FrownyFrog This is a clever way to find the odd character \$\endgroup\$ – Galen Ivanov Nov 28 '17 at 8:25
  • \$\begingroup\$ can’t decide what i like better: this lovely hook or your dragon joke... \$\endgroup\$ – Jonah Nov 28 '17 at 13:46
4
\$\begingroup\$

Brachylog, 8 4 bytes

oḅ∋≠

Try it online!

Explanation

I haven't used Brachylog before, so this may not be optimal.

oḅ∋≠  Input is a string.
o     Sort the input.
 ḅ    Split it into blocks of equal elements.
  ∋   There is a block
   ≠  whose elements are all different.
      That block is the output.
\$\endgroup\$
  • \$\begingroup\$ That use of ∋≠ after to get the results of length 1 is very clever. You should definitely post it in the Brachylog tips question. \$\endgroup\$ – Fatalize Nov 30 '17 at 7:28
  • \$\begingroup\$ @Fatalize Thanks, I added the tip. \$\endgroup\$ – Zgarb Nov 30 '17 at 8:28
3
\$\begingroup\$

K (oK), 7 6 bytes

Solution

*<#:'=

Try it online!

Example:

*<#:'="vvqvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv"
"q"

Explanation:

Found a slightly shorter approach: Evaluated right-to-left:

*<#:'= / the solution
     = / group matching items together
  #:'  / count (#:) each (')
 <     / sort ascending
*      / take the first one

Notes:

Whilst I'm expecting the bonus aspect of this challenge to get dropped, this solution will return the newline character \n if there is no odd character:

*<#:'="vvvvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv\nvvvvvvvvvv"
"\n"
\$\endgroup\$
3
\$\begingroup\$

Prolog (SWI), 46 bytes

p(L):-select(X,L,Y),\+member(X,Y),writef([X]).

Try it online!

Or if the standard true output from prolog queries is not okay:

Prolog (SWI), 48 bytes

Z*L:-select(X,L,Y),\+member(X,Y),char_code(Z,X).

Try it online!

Explanation

Find the first element X in the input  
that when removed, results in output  
that does not contain X

then depending on the version above either:  
print X as a character  
or  
return X as an atom
\$\endgroup\$
3
\$\begingroup\$

C (gcc), 93 92 90 66 62 Bytes

Much shorter as a function

t;f(char*p){for(t=*p;*p;)t^*p++?putchar(*p^*--p?*p:t),*p=0:0;}

Try it online!

test code

main()
{
    char s[99];
    for(;gets(s);)f(s);
}

old version is a program

C 86 Bytes

char*p;s[9];main(t){for(;p=gets(s);)for(t=*p;*p;)t^*p++?putchar(*p^*--p?*p:t),*p=0:0;}

Outputs the odd character, or nothing. run like this;

C:\eng\golf>python matrix_gen.py | a.exe
X
C:\eng\golf>python matrix_gen.py | a.exe
G
C:\eng\golf>python matrix_gen.py | a.exe
x
C:\eng\golf>python matrix_gen.py | a.exe

C:\eng\golf>python matrix_gen.py | a.exe
J
\$\endgroup\$
  • \$\begingroup\$ I don't know that it is quite fair to put the gets() into the test driver as it is sanitizing the input by removing the \n chars for you. That's doing some work so that your function is not working on the original input. \$\endgroup\$ – Michael Dorgan Nov 29 '17 at 23:10
  • \$\begingroup\$ @MichaelDorgan It works with the piped input from the python script as well as input on TIO. Others simply hard-coded the input which didn't seem with the spirit of the challenge. \$\endgroup\$ – cleblanc Nov 30 '17 at 13:45
3
\$\begingroup\$

05AB1E,  4  2 bytes

Saved 2 bytes thanks to Adnan

.m

Try it online!

Explanation

.m   # push a list of the least frequent character(s) in input
\$\endgroup\$
  • \$\begingroup\$ Do you need to remove the newlines, seeing as we're guaranteed the input will be at least 5 lines long? \$\endgroup\$ – Shaggy Nov 28 '17 at 8:19
  • \$\begingroup\$ @Shaggy: No I don't. That was to handle 2x2 matrices. I missed the part about 5x5 and up. Thanks! \$\endgroup\$ – Emigna Nov 28 '17 at 8:44
  • \$\begingroup\$ It has to return nil if it doesn't have an "odd one out" doesn't it? \$\endgroup\$ – Magic Octopus Urn Nov 30 '17 at 0:49
  • \$\begingroup\$ @MagicOctopusUrn That part was optional when this answer was posted. I guess that change invalidates most answers now... \$\endgroup\$ – Martin Ender Nov 30 '17 at 8:49
2
\$\begingroup\$

Retina, 13 bytes

s(O`.
(.)\1+

Try it online!

Explanation

s(O`.

Sort all characters.

(.)\1+

Remove any characters that appear at least twice.

\$\endgroup\$
2
\$\begingroup\$

Husk, 2 bytes

◄=

Try it online!

This is a function taking a string as input and returning a character. It takes the minimum of the input string when comparing characters for equality (i.e. it returns the character that is equal to the least number of other characters).

\$\endgroup\$
2
\$\begingroup\$

C, 94 bytes

Return by pointer. If none, return \0.

This will cause memory leaks. Assuming int is 4 bytes.

*t;f(c,p,i)char*c,*p;{t=calloc(64,8);for(*p=-1;*c;c++)t[*c]--;for(i=0;++i<128;)!~t[i]?*p=i:0;}

Try it online!

\$\endgroup\$
  • 2
    \$\begingroup\$ Functions must be reusable. \$\endgroup\$ – Shaggy Nov 28 '17 at 8:21
  • \$\begingroup\$ @Shaggy Actually, I don't know how to interpret that rule, as I see some (other) users explicitly know about that rule but still post such answers like this one. \$\endgroup\$ – user202729 Nov 28 '17 at 9:44
  • 2
    \$\begingroup\$ @user202729, just because others do it doesn't mean it's right ;) If you spot such solutions, best to point it out to them. \$\endgroup\$ – Shaggy Nov 28 '17 at 9:46
  • \$\begingroup\$ @Shaggy Well, I explicitly pointed the rule but that user said "the rule explicitly says that this one is valid". I don't know what to say. | In this case the function require the array t be zeroed before calling each time not the first time. \$\endgroup\$ – user202729 Nov 28 '17 at 9:50
  • \$\begingroup\$ @Shaggy Thanks, fixed. \$\endgroup\$ – Colera Su Nov 28 '17 at 11:05
2
\$\begingroup\$

Mathematica, 27 bytes

Last@*Keys@*CharacterCounts

Try it online!

-1 byte from Martin Ender

\$\endgroup\$
2
\$\begingroup\$

Bash, 15 20 bytes

fold -1|sort|uniq -u

Try it online!

Explanation: folds the input to 1 character per line, sorts it into groups of matching letters, then prints only lines that are unique.

Thanks @Nahuel Fouilleul for catching and helping fix a problem with this approach.

\$\endgroup\$
  • \$\begingroup\$ doesn't work if the odd character is the second or the penuitlimate \$\endgroup\$ – Nahuel Fouilleul Nov 29 '17 at 14:45
  • \$\begingroup\$ @NahuelFouilleul Good catch... I'm unsure of how to fix that at the moment, but I will fix or delete later unless you had a suggested fix. \$\endgroup\$ – Justin Mariner Nov 29 '17 at 14:50
  • \$\begingroup\$ it can be simply fix with |sort| but there may be a better solution \$\endgroup\$ – Nahuel Fouilleul Nov 29 '17 at 15:38
  • \$\begingroup\$ also found a solution with grep but it's longer grep -oP '^(.)((?=(?!\1).){2}|.*\K(?!\1).)' \$\endgroup\$ – Nahuel Fouilleul Nov 29 '17 at 16:17
  • \$\begingroup\$ @NahuelFouilleul I'm going with the sort fix, thanks. You could always post that grep answer as your own if you want to, though. \$\endgroup\$ – Justin Mariner Nov 29 '17 at 19:56
1
\$\begingroup\$

Pyth, 4 bytes

ho/Q

Try it here!

\$\endgroup\$
  • \$\begingroup\$ .m/Q is 4 bytes as well \$\endgroup\$ – Dave Nov 30 '17 at 12:56
  • \$\begingroup\$ @Dave That outputs as a list though, I chose this because it was more elegant ;-) \$\endgroup\$ – Mr. Xcoder Nov 30 '17 at 12:57
1
\$\begingroup\$

Perl 5, 17 + 3 (-00p) -25% = 15 bytes

/(.)\1/;s/
|$1//g

try it online

\$\endgroup\$
1
\$\begingroup\$

Matlab, 25 Bytes

a=input('');a(a~=mode(a))

The input "a" where "a" isn't the mode of "a". Outputs empty array for no oddball.

\$\endgroup\$
1
\$\begingroup\$

Haskell, 33 * 0.75 = 24.75 bytes

f s=[c|[c]<-(`filter`s).(==)<$>s]

Returns an empty list if there's no odd character.

Try it online!

For each char c in the matrix (given as a string s) make a string of all chars in s that are equal to c and keep those of length 1.

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 37 bytes

Returns null if there's no odd letter.

s=>s.match(`[^
${s.match(/(.)\1/)}]`)

Test cases

let f =

s=>s.match(`[^
${s.match(/(.)\1/)}]`)

console.log(f(
  'bbbbbbbbbb\n' +
  'bbbbbdbbbb\n' +
  'bbbbbbbbbb\n' +
  'bbbbbbbbbb\n' +
  'bbbbbbbbbb'
))

console.log(f(
  'AAAAAAA\n' +
  'AAAAAAA\n' +
  'AAAAAAA\n' +
  'AAAIAAA\n' +
  'AAAAAAA'
))

console.log(f(
  'vvqvvvvvvv\n' +
  'vvvvvvvvvv\n' +
  'vvvvvvvvvv\n' +
  'vvvvvvvvvv\n' +
  'vvvvvvvvvv'
))

console.log(f(
  'puuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu\n' +
  'uuuuuuuuu'
))

console.log(f(
  'AAAAA\n' +
  'AAAAA\n' +
  'AAAAA\n' +
  'AAAAA\n' +
  'AAAAA'
))

\$\endgroup\$
1
\$\begingroup\$

Japt, 6 bytes

Takes input as a multi-line string and outputs a single character string, or an empty string if there's no solution.

k@èX É

Try it


Explanation

Remove the characters that return truthy (k) when passed through a function (@) that counts (è) the occurrences of the current element (X) in the input and subtracts 1 (É).

\$\endgroup\$
1
\$\begingroup\$

Common Lisp, 47 bytes

(lambda(s)(find-if(lambda(x)(=(count x s)1))s))

Try it online!

Returns the odd letter or NIL if it does not exist.

\$\endgroup\$
1
\$\begingroup\$

Jelly, 4 bytes

ċ@ÐṂ

Try it online!

Return \n (a single newline) in case there is no odd character. Obviously \n is not a printable character.

Coincidentally this is exactly the same algorithm as Mr.Xcoder Python answer. (I came up with it independently)

Explanation:

  ÐṂ    Ṃinimum value by...
ċ@      ċount. (the `@` switch the left and right arguments of `ċ`)

That works because in a m×n matrix:

  • If there exists odd character: There are m-1 newlines, 1 odd characters and m×n-1 normal character, and 1 < m-1 < m×n-1 because 5 ≤ m, n ≤ 10.
  • If there doesn't exist odd character: There are m-1 newlines and m×n normal character, and m-1 < m×n.
\$\endgroup\$
1
\$\begingroup\$

C# (.NET Core), 54 bytes

i=>i.GroupBy(x=>x).FirstOrDefault(g=>g.Count()<2)?.Key

Try it online!

\$\endgroup\$
  • \$\begingroup\$ You are right, my answer was wrong. I have deleted it. But you are missing the 18 bytes from the using statement in the byte count. \$\endgroup\$ – raznagul Nov 29 '17 at 13:03
1
\$\begingroup\$

C (gcc), 91 86 82 79 71 bytes

f(char*s){for(;*++s==10?s+=2:0,*s;)if(*s^s[-1])return*s^s[1]?*s:s[-1];}

Try it online!

  • Thanks to Gastropner for the xor and ? tricks (-3 bytes)
  • Reworked the compare version to fix bugs and used Gastropner magic from comments.

Explanation:

Compare current and previous char while skipping newlines. If different, compare to next char. This tells us if we return current or previous char. The function returns the "odd" char value if it exists or 0 if the array is not odd. We get away with the "next" char check because there is always a newline before the \0 char. If there is no odd char, we intrinsically return the \0 from the for loop.


Older, sexier xor code Explanation:

Make a running xor mask of the next 3 string values. If they are all the same, then the value will be equal to any of the three. If they are different, then the 2 identical will cancel each other out leaving the unique.

Must factor /n before the xor or it gets messy. Also have to check 2 chars for inequality in case s[0] is the odd value. This costs the extra || check.

v;f(char*s){while(s[3]){s[2]==10?s+=3:0;v=*s^s[1]^s[2];if(v^‌​*s++||v^*s)break;}}
\$\endgroup\$
  • \$\begingroup\$ 79 with a few tweaks. The fall-through return does not agree with my compiler, so only tested on TIO: v;f(char*s){while(s[3]){s[2]==10?s+=3:0;v=*s^s[1]^s[2];if(v^*s++||v^*s)break;}} \$\endgroup\$ – gastropner Nov 29 '17 at 22:12
  • \$\begingroup\$ For the crap I am writing, TIO is what I stick with. Thanks! \$\endgroup\$ – Michael Dorgan Nov 29 '17 at 22:59
  • \$\begingroup\$ Rearranging some expressions allows another -2 for 77: v;f(char*s){while(s[2]==10?s+=3:0,v=*s^s[1]^s[2],s[3])if(v^*s++||v^*s)break;} However your winning horse is the other one, if you fiddle with it a bit, for 73: v;f(char*s){for(v=-1;*++s==10?s+=2,v--:0,*s;v=0)if(*s^s[-1])return s[v];} \$\endgroup\$ – gastropner Nov 29 '17 at 23:36
  • \$\begingroup\$ Yeah, but the xor seems so sexy. :) \$\endgroup\$ – Michael Dorgan Nov 29 '17 at 23:39
1
\$\begingroup\$

Octave, 26 25 bytes

1 byte saved thanks to @Giuseppe

@(x)x(sum(x(:)==x(:)')<2)

Anonymous function that takes a 2D char array as input, and outputs either the odd letter or an empty string if it doesn't exist.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Alice, 16 * 75% = 12 bytes

/-.nDo&
\i..*N@/

Try it online!

Outputs Jabberwocky if there is no duplicate character.

Explanation

/...@
\.../

This is a framework for linear programs that operate entirely in Ordinal (string processing mode). The actual code is executed in a zigzag manner and unfolds to:

i..DN&-o

i   Read all input.
..  Make two copies.
D   Deduplicate one copy, giving only the two letters and a linefeed.
N   Multiset difference. Removes one copy of each letter and one linefeed.
    Therefore it drops the unique letter.
&-  Fold substring removal over this new string. This essentially removes
    all copies of the repeated letter and all linefeeds from the input,
    leaving only the unique letter.
.   Duplicate.
n   Logical NOT. Turns empty strings into "Jabberwocky" and everything else
    into an empty string.
*   Concatenate to the previous result.
o   Print the unique letter or "Jabberwocky".

Instead of &-, we could also use ey (transliteration to an empty string). Alternatively, by spending one more character on stack manipulation, we could also deduplicate the input which lets us remove the unwanted characters with N, but it's still the same byte count:

i.D.QXN.n*o@

Alice, 13 bytes

/N.-D@
\i&.o/

Try it online!

This is the solution without the bonus, it's simply missing the .n*.

\$\endgroup\$
0
\$\begingroup\$

Retina, 22 bytes

!`(.)(?!.*\1)(?<!\1.+)

Try it online! Only requires height and width of at least 3, rather than 5.

\$\endgroup\$
0
\$\begingroup\$

APL+WIN, 16 bytes

(1=+/a∘.=a)/a←,⎕

Prompts for screen input and either outputs odd letter or nothing if there is no odd letter

\$\endgroup\$
  • \$\begingroup\$ a/⍨1=+/a∘.=a←,⎕ for a byte \$\endgroup\$ – Uriel Nov 28 '17 at 15:16
  • \$\begingroup\$ @Uriel Thanks but I am afraid the operator ⍨ is not available in my old APL+WIN version 5 :( \$\endgroup\$ – Graham Nov 28 '17 at 15:35
0
\$\begingroup\$

PowerShell, 39 bytes

([char[]]"$args"|group|sort c*)[0].Name

Try it online!

Takes input as a string with newlines (as specified in the challenge), converts it to a char-array. We then Group-Object the characters, so that characters are grouped together by their names, then sort based on the count. This ensures that the lonely character is first, so we take the [0] index and output its .Name.

If newline is acceptable for "nothing" then this qualifies for the bonus.

\$\endgroup\$
  • \$\begingroup\$ I was hoping sort c*)[0] could be shortened, but what I came up with was the same number of bytes, ? c* -eq 1). \$\endgroup\$ – root Nov 28 '17 at 21:03
  • \$\begingroup\$ can be shortened by removing the double quotes around $args. Also it is more accurate to do ([char[]]$args|group|? c* -eq 1).Name as it will accurately return null when there is no odd character (instead of new line). However in terms of bytes this still won't bring you below 37. \$\endgroup\$ – cogumel0 Nov 29 '17 at 10:15
  • \$\begingroup\$ @cogumel0 Doesn't run without double quotes. \$\endgroup\$ – root Nov 29 '17 at 13:11
  • \$\begingroup\$ @root you're correct. However to pass one of the requirements (A single character that is the "odd" in the matrix or None, nil, NUL, or the string "None" if there is no "odd" character.) it should still be changed. Newline is not part of the acceptable answers. \$\endgroup\$ – cogumel0 Nov 29 '17 at 14:12
  • \$\begingroup\$ @cogumel0 Ah, the challenge was changed since I posted my answer. The "None / nil / whatever" used to just be a bonus rather than mandatory. I'm going to keep my answer as-is. \$\endgroup\$ – AdmBorkBork Nov 29 '17 at 14:16
0
\$\begingroup\$

Perl 6,  27  24 -25% = 18 bytes

*.comb.Bag.min(*.value).key

Test it

{%(.comb.Bag.invert){1}}

Test it

This will return an undefined value when given an input that doesn't have an odd character out.

Expanded:

{  # bare block lambda with implicit parameter 「$_」

  %(        # coerce into a Hash

    .comb   # split the input into graphemes (implicit method call on 「$_」)
    .Bag    # turn into a weighted Set
    .invert # invert that (swap keys for values) returns a sequence

  ){ 1 }    # get the character that only occurs once
}
\$\endgroup\$
0
\$\begingroup\$

Brainfuck, 125 bytes

,[----------[>],]<[->+<]<<[[->->+<<]>[>[->-<<<+>>]>[,<<,>>]<<<[->+<]>[->+<]<]>[-<<+>>]>[-<+>]<<<<]>>>>[<]<++++++++++.

Try It Online

Prints the letter of the matrix if there is no odd one out

\$\endgroup\$
0
\$\begingroup\$

Java 8, 85 bytes

This is a lambda from String to String (e.g. Function<String, String>). It's essentially a copy of Luca's solution, but I've pared down the string sorting a bit.

s->new String(s.chars().sorted().toArray(),0,s.length()).replaceAll("(.)\\1+|\\n","")

Try It Online

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.