Find the needle in the haystack

39

4

Given a rectangular haystack of size at least 2x2 composed of all the same printable ASCII characters, output the location (counting from the top-left) of the needle which is a different character.

For example, if the following haystack is input:

#####
###N#
#####
#####

The output should be 3,1 when zero-indexed (what I'll be using in this challenge) or 4,2 when one-indexed.

The haystack can be composed of any printable ASCII character:

^^^
^^^
^N^
^^^
^^^
^^^

output: 1,2

and the needle will be any other printable ASCII character:

jjjjjj
j@jjjj
jjjjjj

output 1,1

It's also possible to have a needle in the corner:

Z8
88

output 0,0

88
8Z

output 1,1

or to have the needle at the edge:

>>>>>>>>>>
>>>>>>>>>:
>>>>>>>>>>

output 9,1

Rules and Clarifications

  • Input and output can be given by any convenient method. This means you can take input as a list of list of characters, as a single string, etc.
  • You can print the result to STDOUT or return it as a function result. Please state in your submission what order the output is in (i.e., horizontal then vertical, as used in the challenge, or vice versa).
  • Either a full program or a function are acceptable.
  • You do not get to pick which characters to use. That's the challenge.
  • The haystack is guaranteed to be at least 2x2 in size, so it's unambiguous which is the needle and which is the hay.
  • There is only ever one needle in the input, and it's only ever one character in size.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

AdmBorkBork

Posted 2019-02-01T14:02:26.577

Reputation: 41 581

Suggested test case: 88\n8Z (with any two characters of course). – Kevin Cruijssen – 2019-02-01T14:24:03.643

Can we take input as a multi-dimensional array? i.e. [ ['#','#','#','#','#'], ['#','#','#','N','#'], ['#','#','#','#','#'], ['#','#','#','#','#'] ]; – 640KB – 2019-02-01T14:39:08.053

2@gwaugh Like a list of list of characters? Yes, that's fine (and explicitly called out as OK). – AdmBorkBork – 2019-02-01T14:40:25.973

3Can we take input as a pair of a string without newlines and the width (or height) of the haystack? i.e. ("########N###########", 5) – my pronoun is monicareinstate – 2019-02-01T15:17:50.550

3

@someone Yes, though it doesn't have a real quorum, I feel that should be allowed.

– AdmBorkBork – 2019-02-01T15:32:05.040

On the topic that @someone asked, can we take input as pair of string w/o NL and width as function params? – 640KB – 2019-02-01T19:18:50.153

@gwaugh Yes, that's fine. – AdmBorkBork – 2019-02-01T19:23:02.190

@AdmBorkBork would a numpy array of int32 be fine as input? (note that numpy does have char arrays as well) – ASCII-only – 2019-02-04T08:32:19.137

@ASCII-only If int32 is the only way to take input, that would be OK, but given that char arrays are possible, I'm going to rule that numpy must use char arrays. – AdmBorkBork – 2019-02-04T13:39:43.960

What about ##\n@@ i.e. same amount of both characters – FireCubez – 2019-02-04T20:37:20.853

@FireCubez There's only one needle. I can make that explicitly clear, if you think it's necessary? – AdmBorkBork – 2019-02-04T20:47:29.947

i.e. input is guaranteed to only have one needle? I think you should clear that up, since I got confused at first. – FireCubez – 2019-02-04T20:50:54.150

@FireCubez Added. Thanks! – AdmBorkBork – 2019-02-04T20:56:49.903

"The haystack is guaranteed to be at least 2x2 in size" – does this mean it's guaranteed to be at least 2 wide and 2 high, or that it's guaranteed to be at last 4 characters in area? – Deadcode – 2019-02-04T22:48:41.943

@Deadcode I think also 3x1 or 1x3 may be correct. It could be enough to have one needle different from the rest from my point of view. – AZTECCO – 2019-02-06T00:18:13.100

@Deadcode Guaranteed at least 2 wide and 2 high. While AZTECCO is correct that 1x3 or 3x1 is enough to distinguish the needle and hay, such a situation will never happen. – AdmBorkBork – 2019-02-06T13:48:56.463

Answers

18

R, 49 47 44 bytes

function(m,`?`=which)m==names(?table(m)<2)?T

Try it online!

Takes input as a matrix, returns 1-indexed coordinates

Kirill L.

Posted 2019-02-01T14:02:26.577

Reputation: 6 693

4That which assignment is disgracefully smooth. – CriminallyVulgar – 2019-02-01T15:59:17.733

4I was so excited to try this challenge in R, then I saw this and decided to cry in awe instead – Sumner18 – 2019-02-01T18:41:58.630

9

Perl 6, 41 38 37 bytes

3 bytes saved thanks to @nwellnhof.

1 byte saved thanks to Jo King.

{map {[+] ^∞Z*!<<.&[Z~~]},$_,.&[Z]}

Try it online!

Explanation

It takes the input as a list of lists of characters and returns list of length 2 containing zero-based X and Y coordinates of the needle.

It works by applying the block {[+] ^∞ Z* !<<.&[Z~~]} on the input and on its transpose. .&[Z~~] goes through all columns of the argument and returns True if all the elements are the same, False otherwise. We then negate all the values (so we have a list with one bool per column, where the bool answers the question "Is the needle in that column?"), multiply them element-wise with a sequence 0,1,2,... (True = 1 and False = 0) and sum the list, so the result of the whole block is the 0-based number of the column where the needle was found.

Nwellnhof's better approach, Perl 6, 34 bytes

{map *.first(:k,*.Set>1),.&[Z],$_}

Try it online!

Explanation

Generally the same approach, just more effective. It still uses a block on the array and its transpose, but now the block converts all rows intoSets and checks for the number of elements. The first function then gives index (due to the :k) of the first row that contained more than 1 element. Because of that, the order of $_ and .&[Z] needed to be swapped.

Ramillies

Posted 2019-02-01T14:02:26.577

Reputation: 1 923

Nice approach! 34 bytes with first(:k), Set and .&[Z].

– nwellnhof – 2019-02-01T15:59:41.907

@nwellnhof, very well done. You basically found what I wanted to find but failed to do that :—). (Also I had no idea that you could write .&[Z].) – Ramillies – 2019-02-01T16:31:02.693

In general, .&[op] doesn't seem to be equivalent to [op] $_ but it works with Z for some reason. – nwellnhof – 2019-02-01T18:35:09.007

@JoKing, thanks! – Ramillies – 2019-02-02T12:25:01.547

9

Python 2, 57 bytes

lambda m:[map(len,map(set,a)).index(2)for a in zip(*m),m]

Try it online!


A port of this to Python 3 can be 62 bytes:

lambda m:[[len(set(v))for v in a].index(2)for a in(zip(*m),m)]

The list comprehension, [len(set(v))for v in a], is shorter than the double map by two bytes now as it would need to be cast to a list like list(map(len,map(set,a)))

Try it online!

Jonathan Allan

Posted 2019-02-01T14:02:26.577

Reputation: 67 804

6

Brachylog, 20 bytes

c≡ᵍ∋Ȯ&;I∋₎;J∋₎gȮ∧I;J

Try it online!

Outputs [I,J], where I is the row index and J the column index, both 0-indexed.

Stupidely long, but getting indexes in Brachylog is usually very verbose.

Explanation

c                       Concatenate the Input into a single string
 ≡ᵍ                     Group identical characters together
   ∋Ȯ                   Ȯ is a list of One element, which is the needle character
     &;I∋₎              Take the Ith row of the Input
          ;J∋₎          Take the Jth character of the Ith row
              gȮ        That character, when wrapped in a list, is Ȯ
                ∧I;J    The output is the list [I,J]

Fatalize

Posted 2019-02-01T14:02:26.577

Reputation: 32 976

6

PHP, 99 85 bytes

Using string without newlines and the width (or height) ('########N###########', 5) as input.

  • -5 bytes by removing chr() call, props to @Titus
  • -9 bytes by taking input as two function args, also props to @Titus
function($a,$l){return[($p=strpos($a,array_flip(count_chars($a,1))[1]))%$l,$p/$l|0];}

Try it online!

Ungolfed:

function need_hay( $a, $l ) {

    // identify the "needle" by counting the chars and 
    // looking for the char with exactly 1 occurrence
    // note: this is 1 byte shorter than using array_search()
    $n = array_flip( count_chars( $a, 1 ) )[1];

    // find the location in the input string
    $p = strpos( $a, $n );

    // row is location divided by row length, rounded down
    $r = floor( $p / $l );

    // column is remainder of location divided by row length
    $c = $p % $l;

    return array( $c, $r );

}

Output:

#####
###N#
#####
#####
[3,1]

^^^
^^^
^N^
^^^
^^^
^^^
[1,2]

jjjjjj
j@jjjj
jjjjjj
[1,1]

640KB

Posted 2019-02-01T14:02:26.577

Reputation: 7 149

1>

  • no need for chr: If the second parameter for strpos is an integer, it will be interpreted as an ASCII code. -> -5 bytes. 2) Two function parameters $s,$w can save another 9 bytes.
  • < – Titus – 2019-02-01T18:09:22.273

    @Titus, removing the chr() that's brilliant. Thx! The func params did occur to me too, I just didn't want to run afowl of input req's. I'll clarify w/OP. – 640KB – 2019-02-01T19:17:28.353

    5

    05AB1E, 9 6 bytes

    Saved 3 bytes switching input format.

    Input is taken as a string and a row-length.
    Output is a zero-based list of the form [y, x]

    D.mks‰
    

    Try it online! or as a Test Suite

    Explanation

    D           # duplicate the input string
     .m         # get the least frequent character
       k        # get its index in the string
        s       # swap the row length to the top of the stack
         ‰      # divmod the index of the least frequent char with the row length
    

    Emigna

    Posted 2019-02-01T14:02:26.577

    Reputation: 50 798

    Dang, you beat me to it. Was working on an answer. Had just finished a 13-byter. But yours is way better, so +1 instead. :) Completely forgot about .m.. – Kevin Cruijssen – 2019-02-01T14:14:44.663

    @KevinCruijssen: Yeah. I don't think I've ever used .m before, but I was reasonably sure I'd seen it at some point :) – Emigna – 2019-02-01T14:16:13.650

    5

    Python 3 + NumPy, 75 66 bytes

    -9 bytes thanks to @ASCII-only

    lambda x:where(x.view('i')-median(x.view('i')))
    from numpy import*
    

    Try it online!

    This assumes that the input is a NumPy array. The output is zero-indexed, and first vertical, then horizontal.

    It converts the input from char to int then calculates the median of the array, which will be the haystack character. We subtract that from the array, which makes the needle the only non-zero element. Finally, return the index of that element with numpy.where().

    hbaderts

    Posted 2019-02-01T14:02:26.577

    Reputation: 221

    1Since you know the input will be ASCII (i.e. fits in a byte) why not use uint8 for one byte less? – Draconis – 2019-02-01T20:49:31.273

    1Language has to be "Python 3 + numpy" here since numpy isn't included with the normal Python distribution – ASCII-only – 2019-02-02T08:39:03.943

    @Draconis that was actually my plan, but that introduced zeros between the correct uint8 ASCII-codes. I assume this is because Python3 uses Unicode as standard input format for strings. – hbaderts – 2019-02-04T07:02:17.937

    also it would be nice if you linked "numpy" to numpy's website – ASCII-only – 2019-02-04T07:44:44.000

    74 – ASCII-only – 2019-02-04T08:06:18.620

    Also, might want to ask OP if it's ok to take input already converted to uint32 – ASCII-only – 2019-02-04T08:14:01.570

    69 – ASCII-only – 2019-02-04T08:15:05.243

    166 – ASCII-only – 2019-02-04T08:15:38.753

    Wow nice @ASCII-only. I included this in my answer, please let me know if this is ok with you or if you'd prefer to create a separate answer. – hbaderts – 2019-02-04T08:29:08.820

    1It's fine, after all it's not only based off your solution, but also I don't normally use numpy anyway. Plus, it's kinda unavoidable that a solution might be very similar anyway given that all solutions are public and this is a relatively easy challenge – ASCII-only – 2019-02-04T08:31:05.163

    4

    JavaScript (ES6), 55 bytes

    Takes input as \$(s)(w)\$, where \$s\$ is a string and \$w\$ is the width of the matrix. Returns \$[x,y]\$.

    s=>w=>[(i=s.indexOf(/(.)\1+(.)/.exec(s+s)[2]))%w,i/w|0]
    

    Try it online!


    JavaScript (ES6),  65  64 bytes

    Saved 1 byte thanks to @Neil

    Takes input as a matrix of characters. Returns \$[x,y]\$.

    m=>m.some((r,y)=>r.some((c,x)=>!m[p=[x,y],~y&1].includes(c)))&&p
    

    Try it online!

    How?

    We look for the first character \$c\$ located at \$(x,y)\$ which does not appear anywhere in another row \$r[Y]\$. We can perform this test on any row, as long as \$Y\ne y\$. Because the input matrix is guaranteed to be at least \$2\times 2\$, we can simply use \$Y=0\$ if \$y\$ is odd or \$Y=1\$ if \$y\$ is even.

    Arnauld

    Posted 2019-02-01T14:02:26.577

    Reputation: 111 334

    1~y&1 saves a byte over y&1^1. – Neil – 2019-02-01T16:39:45.637

    4

    Java 8, 132 111 bytes

    m->{int c=m[0][0],i=0,j;for(c=m[1][0]!=c?m[1][1]:c;;i++)for(j=m[i].length;j-->0;)if(m[i][j]!=c)return i+","+j;}
    

    -8 bytes (and -13 more implicitly) thanks to @dana.

    Input as character-matrix.

    Try it online.

    Explanation:

    m->{                    // Method with char-matrix parameter and String return-type
      int c=m[0][0],        //  Character to check, starting at the one at position 0,0
          i=0,j;            //  Index integers
      for(c=m[1][0]!=c?     //  If the second character does not equal the first:
             m[1][1]        //   Use the character at position 1,1 instead
            :c;             //  Else: keep the character the same
          ;i++)             //  Loop `i` from 0 indefinitely upwards:
        for(j=m[i].length;j-->0;)
                            //   Inner loop `j` in the range (amount_of_columns, 0]:
          if(m[i][j]!=c)    //    If the `i,j`'th character doesn't equal our character to check:
            return i+","+j;}//     Return `i,j` as result
    

    Kevin Cruijssen

    Posted 2019-02-01T14:02:26.577

    Reputation: 67 575

    1124 - the final return statement should never get hit. There might be a better way to keep the outer loop going? – dana – 2019-02-02T19:26:59.480

    @dana Thanks! As for: "There might be a better way to keep the outer loop going?", there certainly is; just removing it so it becomes an infinite loop. And then the return""; is unreachable and can be removed as well. :D So -21 bytes thanks to you. – Kevin Cruijssen – 2019-02-02T20:31:58.660

    Interesting... I had tried removing the outer loop condition and was getting an unreachable code error. Didn't know that removing the final return was the fix. – dana – 2019-02-02T21:17:58.170

    What exactly does the --> operator do in the inner loop? I was trying to find the java docs for that syntax but couldnt find anything – KBusc – 2019-02-04T13:24:36.973

    1

    @KBusc It's two operators: i-- and >. :) See this SO answer for more info. So the i > 0 is executed first, checking if i is larger than 0. And then i is decreased by 1 with i--, before it enters the body of the loop.

    – Kevin Cruijssen – 2019-02-04T13:29:41.493

    Huh, neat, I dindt know you could do that. Thanks! – KBusc – 2019-02-04T13:31:21.577

    4

    Jelly, 5 bytes

    Outputs [height, width] (1-indexed).

    ŒĠLÐṂ
    

    Try it online!

    ŒĠLÐṂ – Monadic link / Full program. Takes a list of strings M as input.
    ŒĠ    – Group the multidimensional indices by their values (treating M as a matrix).
      LÐṂ – And retrieve the shortest group of indices (those of the unique character).
    

    Jelly, 5 bytes

    ŒĠḊÐḟ
    

    Try it online!

    Mr. Xcoder

    Posted 2019-02-01T14:02:26.577

    Reputation: 39 774

    4

    Jelly, 4 bytes

    Maybe this could've just been a comment for Mr. Xcoder it is pretty similar...

    ŒĠEƇ
    

    A monadic link accepting the matrix of characters which yields a list of one item, the 1-indexed (row, column) co-ordinate from top-left.
    (...As a full program given an argument formatted such that parsing results in a list of lists of characters -- that is a list of strings in Python format -- the single coordinate is printed.)

    Try it online!

    How?

    ŒĠEƇ - Link: matrix, M
    ŒĠ   - multi-dimensional indices grouped by Value
         -  ...due to the 2*2 minimum size and one needle this will be a list of two lists one
         -     of which will have length one (the needle coordinates as a pair) and the other
         -     containing all other coordinates as pairs
       Ƈ - filter keeping those for which this is truthy:
      E  -   all equal?
         -   ... 1 for the list of length 1, 0 for the list of at least 3 non-equal coordinates
    

    Jonathan Allan

    Posted 2019-02-01T14:02:26.577

    Reputation: 67 804

    1Well... this seems borderline, since the is clever. – Erik the Outgolfer – 2019-02-01T21:29:31.450

    3

    Wolfram Language 37 58 bytes

    My earlier entry did not correctly handle the case where the "odd character out" was at the upper left corner of the matrix. This does.

    #~Position~Keys[TakeSmallest[Counts@Flatten@#,1]][[1]]&
    

    Counts@Flatten@# lists how many of each character are in the array, #.

    TakeSmallest[...,1] returns the least frequent count, in the form of an association rule such as <| "Z"->1|>

    Keys...[[1]] returns the "key" to the only item in the association, that of the least used character. ("Z" in the present case)

    #~Position~... returns then position of the key in the original matrix, #.

    DavidC

    Posted 2019-02-01T14:02:26.577

    Reputation: 24 524

    3

    MATL, 12 8 bytes

    tX:XM-&f
    

    Try it online!

    Using the mode function as the majority-detector. Returns 1-based indices.

     t           % duplicate the input
      X:         % turn the copy into a linear array
        XM       % find the arithmetic mode of that (the 'haystack' character)
          -      % Subtract that from the original input
           &f    % find the position of the non-zero value in that result
    

    -4 characters thanks to @LuisMendo

    sundar - Reinstate Monica

    Posted 2019-02-01T14:02:26.577

    Reputation: 5 296

    1@LuisMendo Thanks. I don't think I knew about the 2 output version of find, even in MATLAB. (Hi, btw!) – sundar - Reinstate Monica – 2019-02-01T17:35:11.730

    3

    Perl 5 -p00, 52 45 bytes

    /^(.)(\1*
    )*(\1*)|^/;$_=$&=~y/
    //.$".length$3
    

    45 bytes

    52 bytes

    How

    • -p00 : like -n but also print, paragraph mode
    • /^(.)(\1* )*(\1*)|^/ : matches either
      • from start $1: first character, $2: repetition (not used), $3: characters before the "needle" in the line, $& whole match
      • or null string (position 0) no capture.
    • $_= : to assign the default input/argument variable
    • so $&=~y/ // the number of newlines of $&
    • .$". : concatenate with $" (space character by default) and concatenate
    • length$3 : the length of $3

    Nahuel Fouilleul

    Posted 2019-02-01T14:02:26.577

    Reputation: 5 582

    3

    R 42 bytes

    function(m)which(ave(m,m,FUN=length)==1,T)
    

    Try it online!

    Input: a haystack matrix m

    Output: (row,col) vector - index starting at 1

    niko

    Posted 2019-02-01T14:02:26.577

    Reputation: 231

    1Nice job, and welcome to PPCG! I believe this is 42 bytes, since the f= can be omitted from the byte count, but not the function(m)=. – BLT – 2019-02-06T19:01:17.473

    @BLT I wasn't sure about that but thanks for the heads up :) – niko – 2019-02-06T22:49:24.197

    2

    C# (Visual C# Interactive Compiler), 109 108 107 bytes

    First() => Last() for -1 byte

    currying for -1 byte thanks to Embodiment of Ignorance

    a=>w=>{var d=a.Where(b=>b!=a[0]).Select(b=>a.IndexOf(b));return d.Count()>1?(0,0):(d.Last()%w,d.Last()/w);}
    

    Try it online!

    my pronoun is monicareinstate

    Posted 2019-02-01T14:02:26.577

    Reputation: 3 111

    2

    J, 22 bytes

    $#:(i.~.{~1 i.~#/.~)@,
    

    Try it online!

    NB. returns answer in (row, column) format.

    Jonah

    Posted 2019-02-01T14:02:26.577

    Reputation: 8 729

    2

    Python 2, 53 47 bytes

    lambda s,w:divmod(s.find(min(s,key=s.count)),w)
    

    Try it online!

    Call as f("########N###########", 5) (allowed in a comment). Outputs (y, x).

    Erik saved 6 bytes, suggesting rearranging the output + using divmod. Thanks!

    Lynn

    Posted 2019-02-01T14:02:26.577

    Reputation: 55 648

    You can reorder the output, so you can use the divmod builtin.

    – Erik the Outgolfer – 2019-02-05T20:44:25.827

    2

    PowerShell, 107 98 82 77 bytes

    $l=@{}
    $args|%{if($_-10){$l.$_+=$x++,+$y}else{$x=0;++$y}}
    $l|% v*|? c*t -eq 2
    

    Try it online!

    Takes a splatted string with LFs. Returns zero-indexed location x,y. Unrolled:

    $locations=@{}                      # make a hashtable. key=char, value=location array
    $args|%{
        if($_-10){                      # if current char is not LF
            $locations.$_+=$x++,+$y     # add $x,$y to hashtable value and move $x to next pos
        }else{
            $x=0;++$y                   # move $x,$y to next line
        }
    }
    $locations|% Values|? Count -eq 2   # find and output location array with 2 elements (x,y)
    

    mazzy

    Posted 2019-02-01T14:02:26.577

    Reputation: 4 832

    1

    Python 3, 93 bytes

    def f(s):x=s.find("\n")+1;return[(i%x,i//x)for i,c in enumerate(s)if s.count(c)<2and" "<c][0]
    

    Try it online!

    Input is taken as a multiline string. Output is 0-indexed

    Black Owl Kai

    Posted 2019-02-01T14:02:26.577

    Reputation: 980

    1

    Octave, 40 bytes

    @(x){[r,c]=find(x-mode(+x(:))) [c,r]}{2}
    

    Port of @sundar's MATL answer. Output is a two-element vector with 1-based column and row indices.

    Try it online!

    Luis Mendo

    Posted 2019-02-01T14:02:26.577

    Reputation: 87 464

    1

    Retina 0.8.2, 41 bytes

    s`(?=(.)+\1)(.*?¶)*(.*)(?!\1|¶).+
    $.3,$#2
    

    Try it online! 0-indexed. Explanation:

    s`
    

    Allow . to match newlines. This costs 3 bytes (3rd byte is the ? before the ) but saves 6 bytes.

    (?=(.)+\1)
    

    Look ahead for two identical characters. \1 then becomes the hay.

    (.*?¶)*
    

    Count the number of newlines before the needle.

    (.*)
    

    Capture the hay to the left of the needle.

    (?!\1|¶)
    

    Ensure that the needle isn't hay or a newline.

    .+
    

    Match the rest of the hay so that the result replaces it.

    $.3,$#2
    

    Output the width of the left hay and the number of newlines.

    Neil

    Posted 2019-02-01T14:02:26.577

    Reputation: 95 035

    1

    C# (Visual C# Interactive Compiler), 82 bytes

    x=>w=>{int y=x.IndexOf(x.GroupBy(c=>c).Last(g=>g.Count()<2).Key);return(y%w,y/w);}
    

    Thanks to dana for shaving off 6 bytes!

    Try it online!

    Old solution, 106 bytes

    n=>m=>{var z=n.Distinct();int d=n.IndexOf(n.Count(c=>c==z.First())>1?z.Last():z.First());return(d%m,d/m);}
    

    Both take input as a string and an integer specifying the amount of columns.

    Try it online!

    Embodiment of Ignorance

    Posted 2019-02-01T14:02:26.577

    Reputation: 7 014

    @dana never knew that Enumerable.Last() accepted a delegate, thanks – Embodiment of Ignorance – 2019-02-02T17:34:59.070

    1

    Python 3, 93 89 85 58 bytes

    Complete rewrite taking input as concatenated string, width:

    lambda g,w:divmod(g.index({g.count(c):c for c in g}[1]),w)
    

    Try it online!


    Original answer:

    def k(g):t=''.join(g);return divmod(t.index({t.count(c):c for c in t}[1]),len(g[0]))
    

    EDIT: Saved 4 bytes by swapping linebreak/indent for semicolons. Saved another 4 bytes by using divmod(thanks @JonathanFrech).

    Try it online!

    I know this could be a lot shorter, but I just wanted to try an approach around this dict comprehension.

    steenbergh

    Posted 2019-02-01T14:02:26.577

    Reputation: 7 772

    1Using divmod would save five bytes. – Jonathan Frech – 2019-02-07T00:54:56.233

    1

    Java 8, 104 Bytes

    (x,w)->{int i=0,p=x.length;for(;i<p;i++)if(x[i]!=x[(i+1)%p]&&x[i]!=x[(i+2)%p])break;return i/w+","+i%w;}
    

    Input is array of char, and integer indicating row width.

    Output is zero-based, vertical then horizontal (i.e., row number then column number)

    Explanation:

    (x,w)->{
        int i=0, p=x.length;
        for (;i<p;i++)          //iterate through characters in x
          if (x[i]!=x[(i+1)%p] && x[i]!=x[(i+2)%p])    //compare x[i] with the two subsequent characters in array, wrapping around if necessary
            break;
        return i/w+","+i%w;}  //return row number then column number, zero-based
    

    jkenney

    Posted 2019-02-01T14:02:26.577

    Reputation: 21

    0

    C# .NET, 133 112 111 bytes

    m=>{var c=m[0][0];c=m[1][0]!=c?m[1][1]:c;for(int i=0,j;;i++)for(j=m[i].Count;j-->0;)if(m[i][j]!=c)return(i,j);}
    

    -1 byte thanks to @EmbodimentOfIgnorance.

    Port of my Java answer, but with a List<List<char>> input and int-tuple output, instead of char[][] input and string output.

    Try it online.

    Kevin Cruijssen

    Posted 2019-02-01T14:02:26.577

    Reputation: 67 575

    1Can't you save two bytes by turning you char[][] into a List<List<char>>? Since List<T>.Count is shorter than Array.Length – Embodiment of Ignorance – 2019-02-02T18:47:28.947

    @EmbodimentofIgnorance Thanks! :) – Kevin Cruijssen – 2019-02-02T20:42:53.433

    0

    MATLAB, 68 22 bytes

    [r,c]=find(v~=v(1));if size(r,1)>1 disp([1,1]);else disp([r,c]);end;

    If I could exclude any one case, such as [1,1] in this solution, I could have saved several bytes.

    Updated solution:

    @(v)find(v-mode(v(:)))
    

    Thanks to @sundar for helping me with the special case problem and saving 42 bytes! Also, thanks to @Luis_Mendo for the suggestions and saving me another 2 bytes!

    DimP

    Posted 2019-02-01T14:02:26.577

    Reputation: 251

    I think you can get rid of the check for [1,1] case by using mode(v(:)) instead of v(1). – sundar - Reinstate Monica – 2019-02-01T17:43:24.113

    You need to wrap your code so that it is a full program or a function; you cannot assume that the input is in a variable v. Also, you can probably replace ~= by -, and remove the final ; – Luis Mendo – 2019-02-01T17:55:30.063

    0

    MATL, 11 bytes

    tX:YmyYk-&f
    

    Output is row, then column; 1-based.

    Try it online!

    Explanation

    t    % Implicit input. Duplicate
    X:   % Linearize into a column
    Ym   % Compute mean (characters are converted to ASCII codes)
    y    % Duplicate from below: pushes input again
    Yk   % Closest value: gives the input value that is closest to the mean
    -    % Subtract, element-wise. Gives non-zero for the value farthest from the mean
    &f   % Two-output find: gives row and column indices of nonzeros. Implicit display
    

    Luis Mendo

    Posted 2019-02-01T14:02:26.577

    Reputation: 87 464

    0

    Pyth, 15 14 12 bytes

    .Dxz-zh.-z{z
    

    Takes input as the length of the row and the input without lines and outputs as [row, column].
    Try it here

    Explanation

    .Dxz-zh.-z{z
           .-z{z    Subtract one of each character from the input.
          h         Take the first.
        -z          Remove all instances from the input.
      xz            Find the remaining character in the input.
    .D          Q   Take the result divmod the (implicit) length of the row.
    

    Old approach

    mxJmt{kdeSJ.TB
    

    Try it here

    Explanation

    mxJmt{kdeSJ.TB
               .TBQ   Take the (implicit) input and its transpose...
    m      d          ... and for each...
       mt{k           ... deduplicate each row...
     xJ     eSJ       ... and find the index of the largest.     
    

    user48543

    Posted 2019-02-01T14:02:26.577

    Reputation:

    0

    Charcoal, 40 bytes

    ≔§⎇⌕θ§θ¹ηθ⁰ζSθW⁼№θζLθ«⊞υωSθ»I⌕Eθ⁼ιζ⁰,ILυ
    

    Try it online! Link is to verbose version of code. I must be doing something wrong because this is almost as long as the Retina answer. Explanation:

    ≔§⎇⌕θ§θ¹ηθ⁰ζ
    

    Check whether the second character in the first string is also the first character, and take the first character of the first string if so otherwise the first character of the second string if not. This is then the hay.

    SθW⁼№θζLθ«⊞υωSθ»
    

    Keep reading strings until a string whose hay is less than its length is found.

    I⌕Eθ⁼ιζ⁰,ILυ
    

    Output the position of the mismatching element and then the number of strings previously read.

    Neil

    Posted 2019-02-01T14:02:26.577

    Reputation: 95 035

    0

    Röda, 81 bytes

    f a{i=indexOf;l=i("
    ",a)+1;chars a|sort|count|[[_2,_1]]|min|i _[1],a|[_%l,_1//l]}
    

    Try it online!

    Takes input as a string containing newline-terminated lines. Returns a stream containing 0-indexed horizontal and vertical indexes.

    fergusq

    Posted 2019-02-01T14:02:26.577

    Reputation: 4 867

    0

    Perl 5 -n0, 77 bytes

    $t=(@b=sort/./g)[0]eq$b[1]?pop@b:$b[0];++$y&/\Q$t/g&&say"$y,",pos for /.+$/mg
    

    Try it online!

    Output is row,column starting from the top left, 1-indexed

    Xcali

    Posted 2019-02-01T14:02:26.577

    Reputation: 7 671

    0

    C (clang), 74 bytes

    h(char*s,z,x){for(s+=z--;*s==*--s|*s==s[-1];)z--;printf("%d,%d",z%x,z/x);}
    

    Try it online!

    DEGOLF

    int h(char*s,int z,int x){// z = string size, x = row size
    
     for(s+=z--;
     // move pointer just over the end of the string 
     // and move z counter to the end of string
    
    *s-*--s?   ==>  *s==*--s|  @ceilingcat suggestion 
     // if the previous element is different we will check if the next element is also different
     // if not the result is 1 and the iteration continue
     // in the first iteration it will be different because the pointer is just  over the end
    
     *s-s[-1]? ==> changed to *s==s[-1]   @ceilingcat suggestion 
     // the second check returns 0 if the char changed again so it was the needle
     // if not it's because in the first iteration the first check finded a difference just because the pointer was just over the end
    
     /*0:1*/   :1;)z--;
    
    
     printf("%d,%d",z%x,z/x);
    }
    

    AZTECCO

    Posted 2019-02-01T14:02:26.577

    Reputation: 2 441

    Thanks again @ceilingcat I should have seen it before :( – AZTECCO – 2019-02-06T19:39:47.197

    0

    Haskell, 64 bytes

    f s=[(r,c)|c<-[0..],r<-[0..length s-1],any(notElem$s!!r!!c)s]!!0
    

    Try it online! f takes a list of lines and returns zero-indexed (row,column).

    Works by iterating through the columns and rows and looking for a character which does not appear on all rows.

    Laikoni

    Posted 2019-02-01T14:02:26.577

    Reputation: 23 676

    0

    APL+WIN, 39 bytes

    Index origin =1. Prompts for character matrix as a string input followed by row width. Outputs row by column index position.

    (,(⍳i÷n)∘.,⍳n←⎕)[((1=+/m∘.≡m)/⍳i←⍴m←⎕)]
    

    Try it online! Courtesy of Dyalog Classic

    Explanation:

    ⍳i←⍴m←⎕ Prompt for string and create a vector of indices from 1 to length string.
    
    (1=+/m∘.≡m) Boolean vector identifying position of unique character in string.
    
    (...)/⍳i Use Boolean to select index position of unique character.
    
    ,⍳n←⎕ Prompt for row width of character matrix and create a vector of indices.
    
    ,(⍳i÷n)∘., Create a nested vector of row by column indices of character matrix.
    
    (...)[...] Select row by column index position of unique character.
    

    Graham

    Posted 2019-02-01T14:02:26.577

    Reputation: 3 184

    0

    Kotlin, 142 bytes

    The result is zero based [vertical,horizontal].

    {d:List<String>->val h=if(d[0][0]!=d[0][1])d[1][0]
    else d[0][0]
    var a=""
    for(r in d.indices)for(c in d[r].indices)if(h!=d[r][c])a="[$r,$c]"
    a}
    

    Try it online!

    JohnWells

    Posted 2019-02-01T14:02:26.577

    Reputation: 611

    0

    Python3

    Well I've never tried to do code golf before and I really can't compete with some of these really good solutions, so I've prepared a long-form answer just to demonstrate how I would solve this problem. This function takes a 2-D list of characters of any size as its input.

    (edited to shorten the function up as much as I could)

    def f(i):
        a = None
        b = 0
        c = None
        d = 0
        h = len(i)
        for y in range(h):
            for x in range(len(i[y])):
                if a == None:
                    a = i[y][x]
                elif a != None:
                    if i[y][x] != a:
                        c = i[y][x]
                if i[y][x] == a:
                    b += 1
                elif i[y][x] == c:
                    d += 1
        if b == 1:
            n = a
        elif d == 1:
            n = c
        for y in range(h):
            for x in range(len(i[y])):
                if i[y][x] == n:
                    return (x, y)
    

    Here is a longer version that demonstrates the example input. If you run this script it will show you the 2-D array and the needle (randomly generated every time) as well as solve it with the find_needle() function.

    # Code golf! Needle in a haystack challenge
    # sgibber2018 (my email handle)
    """
    Notes: I can't really compete with what's already been done but I'm doing
           it just to do it. 
    """
    
    import random
    
    input_height = 10
    input_width = 10
    example_input = [["#" for x in range(input_width)] \
        for y in range(input_height)]
    needle_spot_y = random.randrange(input_height)
    needle_spot_x = random.randrange(input_width)
    example_input[needle_spot_y][needle_spot_x] = "!"
    
    for y in range(input_height):
        print(example_input[y])
    
    # and now for the algorithm itself:
    def find_needle(example_input):
        # declare two variables to count different char types
        c1 = None
        c1_count = 0
        c2 = None
        c2_count = 0
        # iterate through the whole list
        height = len(example_input)
        for y in range(height):
            for x in range(len(example_input[y])):
                # assign c1 or c2 accordingly
                if c1 == None:
                    c1 = example_input[y][x]
                elif c1 != None:
                    if example_input[y][x] != c1:
                        c2 = example_input[y][x]
                # count the symbols based on whether or not they match
                if example_input[y][x] == c1:
                    c1_count += 1
                elif example_input[y][x] == c2:
                    c2_count += 1
        # Find the value with just one increment
        if c1_count == 1:
            needle = c1
        elif c2_count == 1:
            needle = c2
        # go back through the list and find the needle and get it's pos
        for y in range(height):
            for x in range(len(example_input[y])):
                if example_input[y][x] == needle:
                    return (x, y)
    
    print(find_needle(example_input))
    

    The function find_needle() takes a 2-D list and returns the coordinates of the character that only has one count. I could probably shorten this up a little but I don't think I can compete with the existing Python3 answer which is mighty impressive. How do you calculate the size of your answers?

    some_guy632

    Posted 2019-02-01T14:02:26.577

    Reputation: 101

    Done! I'm wary of violating Python's whitespace rules too much but I shortened all the variables. Thanks for the heads up. How do I calculate the bytes? – some_guy632 – 2019-02-04T02:31:55.320

    2

    You can use a number of tools. Here is an environment you can use that counts bytes, if you hit the link button at the top it will even generate an form filled answer for you. Also some tips: most operators =, == etc. don't require space on each side of them, so you can remove that easily, If you want to reply to a user in comments you can use @ <user-name> other wise they are unlikely to see it. Anyway, hope you have fun here!

    – Post Rock Garf Hunter – 2019-02-04T02:41:00.610

    2

    I'd also suggest looking at the Tips for golfing in Python page for some general shortcuts you can take

    – Jo King – 2019-02-04T02:47:16.503

    Welcome to PPCG! I recommend going through the tips as per Jo King's suggestion. RE: "I'm wary of violating Python's whitespace rules" - for code-golf you need to violate whatever saves bytes and still works; however for this challenge we can make do with no newlines at all - the only white-space abuse of the port of my Python 2 answer to Python 3 (at 62 bytes) is to miss the space between ) and for [twice] and between in and ( - and, in fact, no "Python rules" are broken only "style guidelines" (although I don't actually see this one in PEP-8). – Jonathan Allan – 2019-02-04T18:16:18.100

    The current code (using tabs or single spaces in place of four spaces) is 387 bytes. Removing trivial white-space is 347 bytes.

    – Jonathan Allan – 2019-02-04T19:04:02.707

    Employing a bunch of golfing techniques and the fact that we do not need both counts (we are guaranteed a single needle and >=3 others) we can get this method to 158 bytes.

    – Jonathan Allan – 2019-02-04T19:04:34.720

    Wow good tips thanks. I'll employ them on the next one! – some_guy632 – 2019-02-04T22:25:33.310

    0

    C (gcc), 81 bytes

    Takes input as three pointers: one to the array, and two to the dimensions. Returns by modifying the dimensions to be the coordinates of the needle.

    i;f(char*a,int*w,int*h){for(i=0;*a==a[i];i++);i=i-1?i:*a==a[2];*h=i/ *w,*w=i%*w;}
    

    Try it online!

    Degolf

    i;f(char*a,int*w,int*h)
    {
      for(i=0;*a==a[i];i++); // Count the number of elements equal to
                             // the one at (0,0)
      i=i-1?i:*a==a[2];  // Special case i==1, because it is 
              // ambiguous whether the needle is at 0 or 1 there.
      *h=i/ *w,*w=i%*w; // Modify pointers to indicate coordinates.
      // the space between i/ and *w is required, as /* starts a comment
    }
    

    user77406

    Posted 2019-02-01T14:02:26.577

    Reputation:

    Suggest i=*a;i=strspn(a,&i) instead of for(i=0;*a==a[i];i++) – ceilingcat – 2019-02-24T03:05:22.183

    0

    Python 2, 63 bytes

    lambda s,w:divmod(s.find({s.count(c):c for c in s}[1]),w)[::-1]
    

    Try it online!

    Expects a string with no newlines and the width of the haystack as arguments.

    Explanation:

                             # get a dictionary of (number of occurrences : character)
                             {s.count(c):c for c in s}
                             # only one character will have one occurrence, so get that character
                             .........................[1]
                      # get the 0-indexed index of the needle character
                      s.find(............................)
               # flat_index / width will give us how many rows "down" the needle is (the y-value)
               # the remainder will give us how many columns "over" the needle is (the x-value)
               # so take the divmod and reverse the returned values to get (x,y)
               divmod(....................................,w)[::-1]
    # anonymous function, takes haystack string with no newlines and haystack width
    lambda s,w:
    

    Triggernometry

    Posted 2019-02-01T14:02:26.577

    Reputation: 765

    0

    C# (.NET Core), 135 111 bytes

    S=>{for(int x=0,y;;x++)try{for(y=0;;y++)if(S[x][y]!=(S[0][0]==S[0][1]?S[0][0]:S[1][0]))return y+","+x;}catch{}}
    

    Try it online! (111 bytes)
    Try it online! (135 bytes)

    New one:

    for (int x = 0, y; ; x++)
        try
        {
            for (y = 0; ; y++)
                if (S[x][y] != (S[0][0] == S[0][1] ? S[0][0] : S[1][0]))
                    return y + "," + x;
        }
        catch { }
    

    Previous one:

    int i = 0, y;
    var r = "";
    for (; i < S.Length; i++)
        for (y = 0; y < S[i].Length; y++)
            r = S[i][y] != (S[0][0] == S[0][1] ? S[0][0] : S[1][0]) ? i + "," + y : r;
    return r;
    

    Hille

    Posted 2019-02-01T14:02:26.577

    Reputation: 349

    0

    C (VC++) Visual Studio 2017, 538bytes

    well there can be a couple of Bytes be stripped of if the haystack and needle string is Input via command line Parameters but i can not get it to work proberly then so the haystack and needle string is hard coded in the source (ugly….. ) takes 50bytes

    Maybe anyone wants to improve on that

    anyway the Code i came up with is

    #include"stdafx.h"
    #define r v[1][i]
    #define i(x,y) if(x==y)
    void main(){const char*v[]={"haystack.exe","#####\n##+##\0" };int i=0,z=0,s=0,c=r,f=c,a=-1,h=0;do{c=r;i(c,f)a++;i(a,1)h=c;if(h&&c!=h&&c!=10)break;i(c,10){z++;s=0;}}while(s++,i++,c);printf("%d,%d",s-1,z);}
    

    the ungolfed variant is

    #include "stdafx.h"
    
    int main(/*int argc, const char * argv[]*/)
    {
        const char * argv[] = {"haystack.exe","#####\n##+##\0" };
        int i = 0,row = 0, col = 0;
        char character = argv[1][i];
        char firstChar = character;
        int howMany = -1;
        char hay = '\0';
        do
        {
            char character = argv[1][i];
            if (character == firstChar)
            {
                howMany++;
            }
            if (howMany ==1)
            {
                hay = character;
            }
            if ((hay != '\0') && (character != hay)&&(character!='\n'))
            {
                break;
            }
            if (character == '\n')
            {
                row++;
                col = 0;
            }
            col++;
            i++;
        } while (character != '\0');
        printf("%d,%d", col-1, row);
        while (1);
        return 0;
    }
    

    i dont expect this to be explained

    der bender

    Posted 2019-02-01T14:02:26.577

    Reputation: 21

    Welcome to PPCG! I'm not familiar enough with C++ to assist, but I know there's a tips page you can check out.

    – AdmBorkBork – 2019-02-19T13:33:25.880

    0

    Befunge-98 (PyFunge), 62 bytes

    ~:04p~-k#v>~:a-!2j6$_04g-!..@
    -#v_$$1+0>  >~:a
    .;>04g-#;_1+^@.
    

    Try it online!

    Output is: column row

    david

    Posted 2019-02-01T14:02:26.577

    Reputation: 180

    0

    APL (Dyalog Unicode), 9 bytesSBCS

    Anonymous tacit prefix function. In a sense, this is actually a kind of poly-glot, as it takes as argument either a character matrix or a list of strings, with the code meaning something else in each case. Always returns [row,column] in which ever index origin is currently active. (APL lets you choose.)

    ⍸↑=∊~∘∊∩/
    

    Try it online!

    If the argument is a matrix, the function works like this:

    ∩/ intersection reduction of each row. Since there will be at least one all-hay row, this gives us at least one hay character. And since every row has at least one hay character, the intersection will always empty out the row that has the needle character.

    ϵnlist (flatten) this, giving us one or more hay characters

     then…

    ~ remove all such characters from…

     the ϵnlisted (flattened) argument, leaving just the needle

    ↑= Boolean matrix indicating where the matrix equals the needle

    the indices where true

    If the argument is a list of strings, the function works like this:

    ∩/ intersection reduction of the strings. Since only one string will have a needle, and all strings have hay, this will give us one or more hay characters without the needle character.

    ϵnlist (flatten) this, giving us the one or more hay characters

     then…

    ~ remove all such characters from…

     the ϵnlisted (flattened) argument, leaving just the needle

    ↑= Boolean matrix indicating where the matrix constructed by merging the strings equals the needle

    the indices where true

    Adám

    Posted 2019-02-01T14:02:26.577

    Reputation: 37 779