Discussion
Eduard Lebedyuk · May 3

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.
4
0 455
Discussion (33)1
Log in or sign up to continue

My current result: size = 94 84

 

/// 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

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

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 }
}

}

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))
}

One more test case:

set a="abbc", b="abcc"
 
Example

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.

Without loops:

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

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))
}

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

Detector("abbz", "abzz")
Detector("aaz", "azz")
Detector("azz", "aaz")

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

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))
}
 

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

w ##class(z.Scratch).Detector("azazz","zaaza") ;should be 0
1

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.

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
}

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.

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.

 
size = 74

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.

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)

(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.

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)

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

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

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

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

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))
}
 

Excellent work.yes

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

 
size = 68
 
size = 67
 
size = 66

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!

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))
}

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