Heterograms, Palindromes, oh my!

28

1

(First challenge, please let me know if there are any problems with it.)

A heterogram is a word where no letter of the alphabet occurs more than once, and a palindrome is a phrase that is the same backwards and forwards.

The challenge here is to write a piece of code that takes in a word (just letters) as input, and outputs whether or not it is a heterogram (truthy/falsy). The catch is that the program must be a palindrome -- reads the same backwards and forwards. Capitalization doesn't matter here, so for the heterogram to be valid it can't have both q and Q, for instance. No comments are allowed, and you cannot place strings that contain your code (or a significant part of your code) to try to make the palindrome part easy :P

This is code-golf, so shortest code wins. Good luck!

EDIT: Parens, brackets or other symbols that have left and right forms must be reversed approriately for the palindrome part. So (helloolleh) is a palindrome, but (helloolleh( is not. Apparently this is called a convenient palindrome.

EDIT 2: You won't get any empty input, input with multiple words or input with characters other than letters. So don't worry about that :)

a spaghetto

Posted 2015-09-24T14:36:21.493

Reputation: 10 647

Are brackets considered to be equivalent for palindromicity? That is, is (hellolleh) a valid palindrome? Similar for [], {}, and <> (where appropriate). – Glen O – 2015-09-24T15:11:46.600

Yes. Sorry, I should have explained that. – a spaghetto – 2015-09-24T15:21:13.117

What about new lines, will asdsa be considered equal to asd\nsa? – wendelbsilva – 2015-09-24T15:42:06.270

No, they would not be equivalent. – a spaghetto – 2015-09-24T16:01:15.360

5

I believe it's called a convenient palindrome.

– lirtosiast – 2015-09-24T22:36:21.610

Answers

9

Pyth - 11 bytes

(Trailing and leading spaces necessary and counted).

 z.{ z }.z 

Test Suite.

<space>        Suppress print
 z             Input (for palindromness)
.{             Unique - actually does testing
  z            Input
<space>        Suppress print
  }            In operator
   .z          Cached input list
   <space>     At end of program makes empty tuple

Maltysen

Posted 2015-09-24T14:36:21.493

Reputation: 25 023

Mike's Pyth answer converts to lowercase before doing .{, are you sure you don't need to do that too? – Sparr – 2016-12-06T02:54:07.887

18

Pyth, 17 bytes

 Z.{rzZ.q.Zzr}.Z 

Try it online here.

The leading space is necessary. I have counted it and the trailing space in the byte count.

Here's the breakdown:

     z            z is initialized to the input
    r Z           Z is initialized to 0, and r(string)0 converts the string to lowercase
  .{              .{ is pyth's builtin uniqueness test
       .q         .q terminates the program
         .Zzr}    This is just the program mirrored
              .Z  . requires a number to immediately follow it
                  If left blank the parser would throw an error
 Z                This is just mirrored from the end
                  The leading space suppresses the automatic printing of this 0
                  The trailing space mirrors the leading space

Mike Bufardeci

Posted 2015-09-24T14:36:21.493

Reputation: 1 680

3Jeez, and I was worried that this would be too hard... Nice job! – a spaghetto – 2015-09-24T16:15:13.220

2You have a .q in your comments, but a .w in your program. – James Webster – 2015-09-25T07:31:30.210

@JamesWebster Thanks for pointing that out. It should be .q – Mike Bufardeci – 2015-09-25T17:59:33.663

16

Python 3, 125

The main problem is to make the reverse of the code parsable. Then we can let it error out from undefined identifiers.

w=[str.lower][0]((input)())
(print)((max)((map)(w.count,w))<2)
(2>((w,tnuoc.w)(pam))(xam))(tnirp)
(()(tupni))[0][rewol.rts]=w

feersum

Posted 2015-09-24T14:36:21.493

Reputation: 29 566

Very minor point, but from the rules you should change the second < into a >! – Jarmex – 2015-09-24T22:25:06.797

12

Perl, 43 bytes

print+m:^(?!.*(.).*\1|1/*.(.)*.!?)^:m+tnirp

Usage example:

echo "abcde" | perl -n entry.pl

Jarmex

Posted 2015-09-24T14:36:21.493

Reputation: 2 045

Wow, that's amazing. Nice job! – a spaghetto – 2015-09-24T22:18:37.850

6

><>, 137 131 Bytes

When I saw this challenge, I thought ><> might finally be a good choice of language since using it you can mostly ignore palindromes; it is simple to make sure the pointer only stays where it should. While this is true, ><> unfortunately makes golfing conditionals excruciating (or just golfing in general). I hope to use some weird tricks I thought of to compensate for this, but here's a "quick" (not actually, both program-wise and creation-wise) answer. You can try it online here.

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
  ;n1<^  -*48<   .00~<  ;n-10<01-n;  >~00.   >84*-  ^>1n;
<.0e&$v?=@:}:&v?)1:-1lv?("Z":<v?)0:i

Returns 1 for true and -1 for false (I could change it to 0 but the length would stay the same, unfortunately)

As always, let me know if this doesn't work and if you have any ideas on how to golf it down. I tested it against a few test cases, but there always could be an exception.

Here's another version, one that I think is a bit more clever, but alas is ten bytes more. Truthy/falsey values this time are 1 and an error (something smells fishy...):

>i:0(?v>:"Z")?vl: 2(?v&{:@$:@=01-*2.
 < ;n1<^  -*48<f6+0.0<
 &1-:1)e*1.1*e(1:-1& 
>0.0+6f>84*-  ^>1n; > 
.2*-10=@:$@:}&v?)2 :lv?("Z":<v?)0:i<

Explanation:

Here's the code without the part added to make it a palindrome. This one doesn't use the "more clever" tricks I attempted to use for the alternate version, so it's a bit easier to explain (if anyone is interested in an explanation for the "tricks," I'd be happy to give one, though).

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
  ;n1<^  -*48<   .00~<  ;n-10<

Line 1:

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
i:0(?v                                 #Pushes input and directs down if negative
      >:"Z")?v                         #Directs down if input is greater than "Z"
                                       #(reduces lowercase input to uppercase)
              l                        #Pushes length

                                       #Main loop begins
               1-:1(?v                 #Decrements top, and then directs down if less than 1
                      &                #Pushes top of stack onto register (length minus 1)
                       :{              #Duplicates top, shifts stack to the left
                         :@            #Duplicates top, shifts top three values of the stack to the right

                           =?v         #If top two values are equal, directs down
                              $        #Swaps top two values of the stack
                               &       #Pushes register onto stack
                                e0.    #Jumps back to the "1" after "?vl"
                                       #Main loop ends

                                   >   #Makes sure when the pointer jumps back to i it goes the right way

Here's how the convoluted swapping (:{:@=?v$) works -- I'll use a test case of this stack: [5,1,8,1] where the last character is the top.

:{ The top of the stack is duplicated: [5,1,8,1,1], and the stack shifted to the left: [1,8,1,1,5]

:@ The top is duplicated: [1,8,1,1,5,5], then the top three values are shifted to the right: [1,8,1,5,1,5]

=?v Unnecessary for this part of explanation

$ The top value is swapped once more yielding [1,8,1,5], which, if you'll note, is the original stack shifted over once (as if { had been the only command).


So what this does in English ("Thank God, he's actually explaining things") is check the entire stack against the top value and move to a point in the second line if any value equals the top. This checking is done proportionate to how many values there are in the stack (l - 1, where l is the length of the stack) so that all values are checked against each other.

Line 2:

  ;n1<^  -*48<   .00~<  ;n-10<
   n1<                          #If input is less than 0 (i.e. there is none), print 1
  ;                             #and terminate

             <                  #If redirected because input is greater than "Z"
         -*48                   #Push 32, subtract (reducing lowercase to uppercase, numerically)
      ^                         #And move back to the portion that tests if input 
                                #is uppercase (which it will pass now)

                     <          #If counter is less than 1 (for main loop)
                 .00~           #Pop the counter and jump to the beginning (i)

                             <  #If any two values in the stack are equal
                          -10   #Push -1 (subtract 1 from 0)
                        ;n      #Print and terminate

cole

Posted 2015-09-24T14:36:21.493

Reputation: 3 526

Glad to see a ><> answer :) – a spaghetto – 2015-09-25T13:42:13.317

1Also, ><> is a palindrome itself (just not a convenient one) – Jo King – 2019-03-02T11:31:46.910

5

PHP, 126 Bytes

You need to run this with the short_tags ini directive turned off in 5.4 or above.

First golf ever. Two copies, the first prints a whole bunch of garbage with the falsy/truthy result:

<?=var_dump(max(array_count_values(str_split(end($argv))))<2)?><?(2>((((vgra$)dne)tilps_rts)seulav_tnuoc_yarra)xam)pmud_rav=?>

This version will not print any jargon (162 bytes):

<?=var_dump(max(array_count_values(str_split(end($argv))))<2);__halt_compiler()?><?()relipmoc_tlah__;(2>((((vgra$)dne)tilps_rts)seulav_tnuoc_yarra)xam)pmud_rav=?>

Run from the command line with

php -f golf.php heterogram

Probably can be golfed a bit further

Scopey

Posted 2015-09-24T14:36:21.493

Reputation: 151

Clever, though pushing limits of validness. Maybe for the sport think of a solution with comments – Martijn – 2015-09-25T11:24:28.670

Instead of ?><?, you can use //\\. That should remove that requirement. And instead of __halt_compiler() use return; – Ismael Miguel – 2015-09-25T11:24:29.443

Disregard it. You can't use comments. But the return; is still valid. – Ismael Miguel – 2015-09-25T11:47:12.223

2

Brachylog, 3 bytes, language postdates challenge

DdD

Try it online!

This is one of the very few programs that works in both Brachylog 1 and Brachylog 2. The TIO link is to Brachylog 1 for old times' sake. Also unsually for Brachylog, this is a full program, not a function. (Full programs in Brachylog implicitly output booleans, which is just what we want for this question.)

The general principle here is that placing a predicate between a pair of identical uppercase letters is an assertion that the current value is invariant under that predicate. So you often see things like AoA for "is sorted" ("invariant under sorting"); A↔A would (in Brachylog 2) mean "is a palindrome" ("invariant under reversal"), and so on. This program is "invariant under removing duplicates", i.e. "doesn't contain duplicates". It's really convenient that this method of specifying invariance happens to be a palindrome.

user62131

Posted 2015-09-24T14:36:21.493

Reputation:

2

05AB1E, 9 bytes

lDÙQqQÙDl

Try it online.

*insert something about going all the way back to my very first challenge*

Non-competing since 05AB1E was made after this challenge.

Explanation

lDÙQqQÙDl
l           Take input and lowercase it.
 DÙ         Duplicate and uniquify.
   Q        Compare the two strings.
    q       Immediately exit.
     QÙDl   The rest of the program is ignored.

a spaghetto

Posted 2015-09-24T14:36:21.493

Reputation: 10 647

1"Non-competing since 05AB1E was made before this challenge." Perhaps you meant after this challenge? ;) – ETHproductions – 2016-11-03T15:04:28.583

1

Brachylog, 3 bytes

≠ụ≠

Try it online!

The predicate succeeds if the input is a heterogram and fails if it is not.

≠      The characters of the input are all distinct,
 ụ     and when converted to upper case,
  ≠    are still all distinct.

Unrelated String

Posted 2015-09-24T14:36:21.493

Reputation: 5 300

0

MATL, 7 bytes

tuX=Xut

Try it online!

Returns list [1, 1] if the input is a heterogram and [0, 0] if not.

Explanation:

t       % duplicate the input
u       % remove duplicates from the original
X=      % check the two lists are equal
Xu      % unique rows (does nothing as we now have a boolean)
t       % duplicate the result
        % (implicit) convert to string and display

B. Mehta

Posted 2015-09-24T14:36:21.493

Reputation: 763