Written by

Senior Cloud Architect at InterSystems
Discussion Eduard Lebedyuk · May 3, 2022

Code Golf: Anagram Detector

An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. For example, the word anagram itself can be rearranged into nag a ram, also the word binary into brainy and the word adobe into abode. Wikipedia

You will receive two strings returning true if the two arguments given are anagrams of each other. As usual shortest solution wins.

##Input "Listen", "Silent"

##Output 1

##Note

Rules

  1. The signature of the contest entry MUST be:
Class codeGolf.Anagram
{

ClassMethod Detector(a As %String, b As %String) As %Boolean
{
  ; your code here
}

}

  1. It is forbidden to modify class/signature, including but not limited to:
  • Adding inheritance
  • Setting default argument values
  • Adding class elements (Parameters, Methods, Includes, etc).
  1. It is forbidden to refer to non-system code from your entry. For example, this is not a valid entry:
ClassMethod Detector(a As %String, b As %String) As %Boolean
{
  q ##class(myPackage.myClass).test(a)
}
  1. The use of $ZWPACK and $ZWBPACK is also discouraged.

Comments

Vitaliy Serdtsev · May 3, 2022

My current result: size = 9484

 
ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 s:$l(a)>$l(bi=b,b=a,a=i=1:1:$l(a){b=$replace(b,$e(a,i),"",,1,1)b?." "
}
0
Stuart Strickland · May 4, 2022

/// using first string replace with null each 'same' character found in second string leaving null or spaces
ClassMethod Detector(As %String, As %String) As %Boolean
{
$$r(a,b)_$$r(b,a)?." "
r(x,y) f  x=$replace(x,$e(y),"",,1,1),$e(y)="" ret:y="" x
}
/// 88 chars

0
Eduard Lebedyuk  May 6, 2022 to Stuart Strickland

Nice use of routines. I think it's a first time we're seen routines in classmethods for code golf.

0
Mindy Caldwell · May 5, 2022

Well,  I won't win any prizes but I just wanted to rejoice in writing my first classmethod in objectscript.

Here is my less than elegant solution

ClassMethod Detector(a As %String, b As %String) As %Boolean
{
  SET a=$CHANGE(a," ","")
  SET a=$ZCVT(a,"l")
  SET b=$CHANGE(b," ","")
  SET b=$ZCVT(b,"l")
  SET c = ""
  FOR i = 1 :1 :$L(a)
  {
    SET p = $F(b,$E(a,1))
    if p { SET $E(b,p-1)="" } else { set c=c_$E(a,1) }
    set $E(a,1)=""
  }
  if ($L(a) + $L(b) + $L(c) ) { q 0 } else { q 1 }
}

}
0
Alexey Maslov · May 8, 2022

size = 83

ClassMethod Detector(As %String, As %String) As %Boolean{
  c="a","b"{@c=$zstrip($zcvt(@c,"U"),"*W")$tr(a,b)=$tr(b,a)&($l(a)=$l(b))}
0
Julius Kavay  May 8, 2022 to Alexey Maslov

One more test case:

set a="abbc", b="abcc"
0
Vitaliy Serdtsev  May 10, 2022 to Alexey Maslov
 

Example

Class dc.golf.Anagram
{

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
  c="a","b"{
    @c=$zstrip($zcvt(@c,"U"),"*W")
  }
  w $$$quote(a),":",$l(a)," - ",$$$quote(b),":",$l(b),!
  q $tr(a,b)=$tr(b,a)&($l(a)=$l(b))
}

}

Output (tested on IRIS 2021.2CE):

USER>##class(dc.golf.Anagram).Detector("apple""pale")
 
<UNDEFINED>zDetector+2^dc.golf.Anagram.1 *a

If I change Undefined, then there is no error, but the result is incorrect:

USER>d $system.Process.Undefined(2)
 
USER>##class(dc.golf.Anagram).Detector("apple""pale")
"apple":5 - "pale":4
0

The code works correctly if change the signature of the method (ProcedureBlock/PublicList/new), but this is a violation of the conditions of the task.

0
Vitaliy Serdtsev  May 13, 2022 to Alexey Maslov

Without loops:

 

size = 82 (likely the code can be further reduced)

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 a=$zu(28,a,6),b=$zu(28,b,6) q $l(a)=$l(b)&(a'=$tr(a,b,a_b))&(b'=$tr(b,a,b_a))
 ;or
 a=$zu(28,a,6),b=$zu(28,b,6) q $l(a)=$l(b)&(a'=$tr(a,b,a_b))&(a'=$tr(a,a_b,b))
}
0
Alexey Maslov  May 13, 2022 to Vitaliy Serdtsev

Yes, it can be, while this approach can't win, as I already understood. Size = 67: 

ClassMethod Detector(As %String, As %String) As %Boolean{
 a=$zu(28,a,6),b=$zu(28,b,6) $tr(a,b)=$tr(b,a)&($l(a)=$l(b))}
0
Vitaliy Serdtsev  May 13, 2022 to Alexey Maslov

It gives an incorrect result for some data, for example:

Detector("abbz", "abzz")
Detector("aaz", "azz")
Detector("azz", "aaz")
0
Alexey Maslov  May 13, 2022 to Vitaliy Serdtsev

So, my feeling was right... It's time to quit this golf club for now, at least for me )))

0
Stuart Strickland  May 13, 2022 to Alexey Maslov

I think you should have kept going Alexey. I was trying to ignore this page but it can be addictive. With a little tweak the $TRANSLATE works AND solves the problem in 64 characters and takes the lead.

ClassMethod Detector(As %String, As %String) As %Boolean
{
 a=$zu(28,a,6),b=$zu(28,b,6) $l($tr(a,b,a))=$l($tr(b,a,b))
}
 

0
Alexey Maslov  May 13, 2022 to Stuart Strickland

Alas, it has the similar problem as my original solution: 

w ##class(z.Scratch).Detector("azazz","zaaza") ;should be 01
0
Stuart Strickland  May 13, 2022 to Alexey Maslov

Ah, you are correct. My test cases for a fail were of differing lengths. Doh!

What is needed is a simple command to sort the letters into a consistent order before comparison.

0
Stuart Strickland · May 10, 2022

How about 76 characters?

/// use $Length to count the occurrences of each letter!
/// store the counts in a list where the piece number is the ascii letter number
/// compare the lists for each word/phrase
ClassMethod Detector(As %String, As %String) As %Boolean
{
$$r(a)=$$r(b)
r(x) i=65:1:90 $li(y,i)=$l($zcvt(x,"u"),$c(i))
 y
}

0
Stuart Strickland  May 10, 2022 to Stuart Strickland

You could save another character by using $Extract instead of $List but that won't work if there are more than 8 of the same letter in the anagram.

0
Stuart Strickland  May 10, 2022 to Vitaliy Serdtsev

Is there a little arrow below my 76 characters that will show my code when you click it? I can't see one under your 73 characters.

0
Vitaliy Serdtsev  May 11, 2022 to Stuart Strickland
 

size = 74

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 q $$r(a)=$$r(b)
r(x)i=65:1:90{s $li(y,i)=$l($zcvt(x,"u"),$c(i))y
}

I'm not publishing the option with size = 73 yet, to wait, maybe someone will guess how to do it or offer an ever shorter option (by analogy with Code Golf - Encoder).

UPD: I managed to reduce size to 72.

0
Stuart Strickland  May 11, 2022 to Vitaliy Serdtsev

Good work. I didn't know you could omit the space after the closing bracket on the line tag arguments.

Also didn't think using curly braces would save anything in this case but it looks like a new line counts as 2 characters with the code length calculator.

(And I think you may be waiting a long time for the Encoder game to close)

0
Vitaliy Serdtsev  May 11, 2022 to Stuart Strickland
(And I think you may be waiting a long time for the Encoder game to close)
The author seems to have forgotten or this no longer relevant. I'm not interested in opening code when there are no alternatives and there is no competitive spirit.
0
Stuart Strickland  May 11, 2022 to Vitaliy Serdtsev

Also got down to 73. Can't get to 72. Changing $LIST to $EXTRACT is shorter but doesn't always work. Changing FOR loop to start from a single digit doesn't work because it would count space characters when it reaches 32.

x=a,b{i=65:1:90{$li(x(x),i)=$l($zcvt(x,"u"),$c(i))}} x(a)=x(b)

0
Stuart Strickland  May 11, 2022 to Stuart Strickland

I thought up some slightly different logic and have got it in 69. It's also more efficient.

0
Julius Kavay  May 11, 2022 to Stuart Strickland

The challenge talks about "...rearranging the letters ...", there is no restriction for the ASCII sequence, so this would not work with cyrillic character set :

CMOKBA  (fig tree, russian)
MOCKBA  (Moscow, capital city)

justmy2cents

0
Stuart Strickland  May 11, 2022 to Julius Kavay

Hi Julius, you may have missed this note in the challenge:

Both arguments are case insensitive, only a-z, A-Z, no special characters except whitespace

0
Julius Kavay  May 15, 2022 to Stuart Strickland

You are right, that's my fault. I didn't read the Notes, just the beginning of the challenge. Sorry.

0
Stuart Strickland · May 12, 2022

Here is the code for a 69 character answer

/// 73 characters:
/// f x=a,b{f i=65:1:90{s $li(x(x),i)=$l($zcvt(x,"u"),$c(i))}} q x(a)=x(b)
/// 
/// but this one is 69:
/// 
/// loop ascii number from "A" to "Z" and "[", that's 65 to 91
/// if count of each letter in each string is different then quit loop
/// if loop reached 91 then loop completed and letter counts must be same in both strings
/// if loop didn't reach 91 then must be counts must be different
ClassMethod Detector(As %String, As %String) As %Boolean
{
 i=65:1:91{q:$$r(a)'=$$r(b)i=91
r(x)$l($zcvt(x,"u"),$c(i))
}
 

0
Vitaliy Serdtsev  May 12, 2022 to Stuart Strickland

Excellent work.yes

You have come up with an additional optimization different from mine. Your code can be improved to 66.

 

size = 68

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 i=65:1:91{q:$$r(a)'=$$r(b)i=91
r(x)q $l($$$UPPER(x),$c(i))
}
 

size = 67

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 i=0:1:91{q:$$r(a)'=$$r(b)i=91
r(x)q $l($zu(28,x,6),$c(i))
}

$$$ALPHAUP(x) == $zu(28,x,6)

 

size = 66

ClassMethod Detector(
  As %String,
  As %StringAs %Boolean
{
 i=90:-1:0{q:$$r(a)'=$$r(b)'i
r(x)q $l($zu(28,x,6),$c(i))
}
0
Stuart Strickland  May 12, 2022 to Vitaliy Serdtsev

I should pay more attention to the $$$MACROs in future!

$ZU(28 is great, it's a shame that Intersystems don't document enough $ZU functions?

The FOR loops that range from 0 to 90/91 don't work with anagrams that contain different numbers of spaces because i=32 checks spaces. E.g. w ##class(CodeGolf.Anagram).Detector("New York Times","monkeys write")

Ah! I stand corrected. Just read %SYSTEM.Util  ALPHAUP removes spaces!

0
Stuart Strickland  May 12, 2022 to Vitaliy Serdtsev

Don't know why I didn't think of this earlier - perhaps it's been a long time since we were forced to minimize characters when writing code. Here's a version that only uses 65.

ClassMethod Detector3(As %String, As %String) As %Boolean
{
 i=91:-1:0{q:$$r(a)-$$r(b)'i
r(x)$l($zu(28,x,6),$c(i))
}

0
Vitaliy Serdtsev  May 12, 2022 to Stuart Strickland

This is the case when don't know whether to stop or continue.smiley

0