Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d466be9

Browse files
fahimfaisaalraklaptudirm
andauthored
merge: Upgrade checkAnagram function & Fixes (#902)
* pref: optimize the algo via reduce & replace method * feat: add TypeError for invalid types * test: upgrade test case for invalid types * docs: add js doc * test: modify the case-sensitive test case * pref: Optimize algo & add case-insensitive mode * style: format with standard style * docs: fix the js doc * docs: rename function name & add comments * feat: add chackAnagramViaMap function * test: add test case for checkAnagramViaMap func * fix: remove **Via** from functions name * style: fix alignment of js doc * chore: grammar fix Co-authored-by: Rak Laptudirm <raklaptudirm@gmail.com>
1 parent 0178efd commit d466be9

File tree

2 files changed

+168
-46
lines changed

2 files changed

+168
-46
lines changed

‎String/CheckAnagram.js‎

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,76 @@
1-
// An [Anagram](https://en.wikipedia.org/wiki/Anagram) is a string that is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
2-
// Anagram check is case sensitive; i.e. Aba and aba is not a anagram.
3-
// inputs are strings i.e. str1 and str2
4-
const checkAnagram = (str1, str2) => {
1+
// An [Anagram](https://en.wikipedia.org/wiki/Anagram) is a string that is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. Anagram check is not case-sensitive;
2+
/**
3+
* @function checkAnagramRegex
4+
* @param {string} str1
5+
* @param {string} str2
6+
* @returns {boolean}
7+
* @description - check anagram with the help of Regex
8+
* @example - checkAnagramRegex('node', 'deno') => true
9+
* @example - checkAnagramRegex('Eleven plus two', 'Twelve plus one') => true
10+
*/
11+
const checkAnagramRegex = (str1, str2) => {
512
// check that inputs are strings.
613
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
7-
return'Not string(s)'
14+
thrownewTypeError('Both arguments should be strings.')
815
}
916

1017
// If both strings have not same lengths then they can not be anagram.
1118
if (str1.length !== str2.length) {
1219
return false
1320
}
1421

15-
// Use hashmap to keep count of characters in str1
22+
/**
23+
* str1 converted to an array and traverse each letter of str1 by reduce method
24+
* reduce method return string which is empty or not.
25+
* if it returns empty string '' -> falsy, with Logical !(NOT) Operator, it's will be converted to boolean and return true else false
26+
*/
27+
return ![...str1].reduce(
28+
(str2Acc, cur) => str2Acc.replace(new RegExp(cur, 'i'), ''), // remove the similar letter from str2Acc in case-insensitive
29+
str2
30+
)
31+
}
1632

17-
const str1CharCount = new Map()
33+
/**
34+
* @function checkAnagramMap
35+
* @description - check anagram via using HashMap
36+
* @param {string} str1
37+
* @param {string} str2
38+
* @returns {boolean}
39+
* @example - checkAnagramMap('node', 'deno') => true
40+
* @example - checkAnagramMap('Eleven plus two', 'Twelve plus one') => true
41+
*/
42+
const checkAnagramMap = (str1, str2) => {
43+
// check that inputs are strings.
44+
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
45+
throw new TypeError('Both arguments should be strings.')
46+
}
1847

19-
for (let i = 0; i < str1.length; i++) {
20-
let previousCount = 0
21-
if (str1CharCount.has(str1[i])) {
22-
previousCount = str1CharCount.get(str1[i])
23-
}
24-
str1CharCount.set(str1[i], previousCount + 1)
48+
// If both strings have not same lengths then they can not be anagram.
49+
if (str1.length !== str2.length) {
50+
return false
2551
}
2652

27-
// Now check if second string has same characters?
53+
conststr1List=Array.from(str1.toUpperCase())// str1 to array
2854

29-
for (let i = 0; i < str2.length; i++) {
30-
let previousCount = 0
31-
// if str1CharCount has no key for str2[i] then not anagram.
32-
if (!str1CharCount.has(str2[i])) return false
55+
// get the occurrences of str1 characters by using HashMap
56+
const str1Occurs = str1List.reduce(
57+
(map, char) => map.set(char, map.get(char) + 1 || 1),
58+
new Map()
59+
)
3360

34-
previousCount = str1CharCount.get(str2[i])
35-
str1CharCount.set(str2[i], previousCount - 1)
36-
}
61+
for (const char of str2.toUpperCase()) {
62+
// if char has not exist to the map it's return false
63+
if (!str1Occurs.has(char)) {
64+
return false
65+
}
3766

38-
// Now check if all entries in hashmap has zeros.
67+
let getCharCount = str1Occurs.get(char)
68+
str1Occurs.set(char, --getCharCount)
3969

40-
for (const key in str1CharCount) {
41-
if (str1CharCount[key] !== 0) return false
70+
getCharCount === 0 && str1Occurs.delete(char)
4271
}
4372

4473
return true
4574
}
4675

47-
export { checkAnagram }
76+
export { checkAnagramRegex,checkAnagramMap }

‎String/test/CheckAnagram.test.js‎

Lines changed: 114 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { checkAnagram } from '../CheckAnagram'
1+
import { checkAnagramMap,checkAnagramRegex } from '../CheckAnagram'
22

3-
describe('checkAnagram', () => {
3+
describe('Testing checkAnagramRegex', () => {
44
it.each`
55
inputOne | inputTwo
66
${123456} | ${'abcd'}
@@ -10,79 +10,172 @@ describe('checkAnagram', () => {
1010
${'abcd'} | ${[1, 2, 3, 4, 5, 6]}
1111
${'abcd'} | ${{ test: 'test' }}
1212
`(
13-
'expects to return "Not string(s)" given values $inputOne and $inputTwo',
13+
'expects to throw the type Error given values $inputOne and $inputTwo',
1414
({ inputOne, inputTwo }) => {
15-
const SUT = checkAnagram(inputOne, inputTwo)
16-
expect(SUT).toBe('Not string(s)')
15+
expect(
16+
() => checkAnagramRegex(inputOne, inputTwo)
17+
).toThrowError()
1718
}
1819
)
1920

2021
it('expects to return false if the arguments have different lengths', () => {
21-
const SUT = checkAnagram('abs', 'abds')
22+
const SUT = checkAnagramRegex('abs', 'abds')
2223
expect(SUT).toBe(false)
2324
})
2425

2526
it('expects to return false if the arguments are not anagrams', () => {
26-
const SUT = checkAnagram('abcs', 'abds')
27+
const SUT = checkAnagramRegex('abcs', 'abds')
2728
expect(SUT).toBe(false)
2829
})
2930

3031
it('expects to return true if the arguments are anagrams', () => {
31-
const SUT = checkAnagram('abcd', 'bcad')
32+
const SUT = checkAnagramRegex('abcd', 'bcad')
3233
expect(SUT).toBe(true)
3334
})
3435

3536
it('expects to return true if the arguments of length 1 and are the same letter', () => {
36-
const SUT = checkAnagram('a', 'a')
37+
const SUT = checkAnagramRegex('a', 'a')
3738
expect(SUT).toBe(true)
3839
})
3940

4041
it('expects to return true if the arguments of are both empty strings', () => {
41-
const SUT = checkAnagram('', '')
42+
const SUT = checkAnagramRegex('', '')
4243
expect(SUT).toBe(true)
4344
})
4445

4546
it('expects to return true if the arguments are anagrams with an odd length', () => {
46-
const SUT = checkAnagram('abcde', 'edcab')
47+
const SUT = checkAnagramRegex('abcde', 'edcab')
4748
expect(SUT).toBe(true)
4849
})
4950

5051
it('expects to return true if the arguments are anagrams with an even length', () => {
51-
const SUT = checkAnagram('abcdef', 'fedcab')
52+
const SUT = checkAnagramRegex('abcdef', 'fedcab')
5253
expect(SUT).toBe(true)
5354
})
5455

5556
it('expects to return false if either argument is an empty string while the other is not', () => {
56-
const SUT = checkAnagram('', 'edcab')
57+
const SUT = checkAnagramRegex('', 'edcab')
5758
expect(SUT).toBe(false)
58-
const SUT2 = checkAnagram('edcab', '')
59+
const SUT2 = checkAnagramRegex('edcab', '')
5960
expect(SUT2).toBe(false)
6061
})
6162

62-
it('expects to return false if the arguments contain the same letters but have unequal case', () => {
63-
const SUT = checkAnagram('ABDCE', 'abcde')
63+
it('expects to return true if the arguments contain the same letters but have unequal case', () => {
64+
const SUT = checkAnagramRegex('ABDCE', 'abcde')
65+
expect(SUT).toBe(true)
66+
const SUT2 = checkAnagramRegex('AbCdE', 'aBCdE')
67+
expect(SUT2).toBe(true)
68+
const SUT3 = checkAnagramRegex('Eleven plus two', 'Twelve plus one')
69+
expect(SUT3).toBe(true)
70+
})
71+
72+
it('expects to return true if the arguments are anagrams and contain number characters', () => {
73+
const SUT = checkAnagramRegex('a1b2', '12ba')
74+
expect(SUT).toBe(true)
75+
})
76+
77+
it('expects to return true if the arguments are anagrams and contain space characters', () => {
78+
const SUT = checkAnagramRegex('a1 b2', '1 2ba')
79+
expect(SUT).toBe(true)
80+
})
81+
82+
it('expects to return true if the arguments are anagrams and contain punctuation characters', () => {
83+
const SUT = checkAnagramRegex('a!1b@2', '1@2ba!')
84+
expect(SUT).toBe(true)
85+
})
86+
87+
it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => {
88+
const SUT = checkAnagramRegex('ea cb', 'e cba')
6489
expect(SUT).toBe(false)
65-
const SUT2 = checkAnagram('AbCdE', 'aBCdE')
90+
})
91+
})
92+
93+
describe('Testing checkAnagramMap', () => {
94+
it.each`
95+
inputOne | inputTwo
96+
${123456} | ${'abcd'}
97+
${[1, 2, 3, 4, 5, 6]} | ${'abcd'}
98+
${{ test: 'test' }} | ${'abcd'}
99+
${'abcd'} | ${123456}
100+
${'abcd'} | ${[1, 2, 3, 4, 5, 6]}
101+
${'abcd'} | ${{ test: 'test' }}
102+
`(
103+
'expects to throw the type Error given values $inputOne and $inputTwo',
104+
({ inputOne, inputTwo }) => {
105+
expect(
106+
() => checkAnagramMap(inputOne, inputTwo)
107+
).toThrowError()
108+
}
109+
)
110+
111+
it('expects to return false if the arguments have different lengths', () => {
112+
const SUT = checkAnagramMap('abs', 'abds')
113+
expect(SUT).toBe(false)
114+
})
115+
116+
it('expects to return false if the arguments are not anagrams', () => {
117+
const SUT = checkAnagramMap('abcs', 'abds')
118+
expect(SUT).toBe(false)
119+
})
120+
121+
it('expects to return true if the arguments are anagrams', () => {
122+
const SUT = checkAnagramMap('abcd', 'bcad')
123+
expect(SUT).toBe(true)
124+
})
125+
126+
it('expects to return true if the arguments of length 1 and are the same letter', () => {
127+
const SUT = checkAnagramMap('a', 'a')
128+
expect(SUT).toBe(true)
129+
})
130+
131+
it('expects to return true if the arguments of are both empty strings', () => {
132+
const SUT = checkAnagramMap('', '')
133+
expect(SUT).toBe(true)
134+
})
135+
136+
it('expects to return true if the arguments are anagrams with an odd length', () => {
137+
const SUT = checkAnagramMap('abcde', 'edcab')
138+
expect(SUT).toBe(true)
139+
})
140+
141+
it('expects to return true if the arguments are anagrams with an even length', () => {
142+
const SUT = checkAnagramMap('abcdef', 'fedcab')
143+
expect(SUT).toBe(true)
144+
})
145+
146+
it('expects to return false if either argument is an empty string while the other is not', () => {
147+
const SUT = checkAnagramMap('', 'edcab')
148+
expect(SUT).toBe(false)
149+
const SUT2 = checkAnagramMap('edcab', '')
66150
expect(SUT2).toBe(false)
67151
})
68152

153+
it('expects to return true if the arguments contain the same letters but have unequal case', () => {
154+
const SUT = checkAnagramMap('ABDCE', 'abcde')
155+
expect(SUT).toBe(true)
156+
const SUT2 = checkAnagramMap('AbCdE', 'aBCdE')
157+
expect(SUT2).toBe(true)
158+
const SUT3 = checkAnagramMap('Eleven plus two', 'Twelve plus one')
159+
expect(SUT3).toBe(true)
160+
})
161+
69162
it('expects to return true if the arguments are anagrams and contain number characters', () => {
70-
const SUT = checkAnagram('a1b2', '12ba')
163+
const SUT = checkAnagramMap('a1b2', '12ba')
71164
expect(SUT).toBe(true)
72165
})
73166

74167
it('expects to return true if the arguments are anagrams and contain space characters', () => {
75-
const SUT = checkAnagram('a1 b2', '1 2ba')
168+
const SUT = checkAnagramMap('a1 b2', '1 2ba')
76169
expect(SUT).toBe(true)
77170
})
78171

79172
it('expects to return true if the arguments are anagrams and contain punctuation characters', () => {
80-
const SUT = checkAnagram('a!1b@2', '1@2ba!')
173+
const SUT = checkAnagramMap('a!1b@2', '1@2ba!')
81174
expect(SUT).toBe(true)
82175
})
83176

84177
it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => {
85-
const SUT = checkAnagram('ea cb', 'e cba')
178+
const SUT = checkAnagramMap('ea cb', 'e cba')
86179
expect(SUT).toBe(false)
87180
})
88181
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /