Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 17 additions & 69 deletions String/CheckAnagram.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,23 @@
// 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;
/**
* @function checkAnagramRegex
* @param {string} str1
* @param {string} str2
* @returns {boolean}
* @description - check anagram with the help of Regex
* @example - checkAnagramRegex('node', 'deno') => true
* @example - checkAnagramRegex('Eleven plus two', 'Twelve plus one') => true
* @function checkAnagram
* @description An anagram is a word or phrase formed by rearranging the
* letters of another word or phrase. This function checks if two strings
* are anagrams of each other, ignoring case and spaces.
* @param {string} str1 - The first input string
* @param {string} str2 - The second input string
* @returns {boolean} - True if the strings are anagrams, false otherwise
* @see https://en.wikipedia.org/wiki/Anagram
* @example checkAnagram("listen", "silent") => true
* @example checkAnagram("hello", "world") => false
* @example checkAnagram("Astronomer", "Moon starer") => true
*/
const checkAnagramRegex = (str1, str2) => {
// check that inputs are strings.
const checkAnagram = (str1, str2) => {
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
throw new TypeError('Both arguments should be strings.')
throw new TypeError('Both inputs must be strings')
}

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

/**
* str1 converted to an array and traverse each letter of str1 by reduce method
* reduce method return string which is empty or not.
*/
return ![...str1].reduce(
(str2Acc, cur) => str2Acc.replace(new RegExp(cur, 'i'), ''), // remove the similar letter from str2Acc in case-insensitive
str2
)
}

/**
* @function checkAnagramMap
* @description - check anagram via using HashMap
* @param {string} str1
* @param {string} str2
* @returns {boolean}
* @example - checkAnagramMap('node', 'deno') => true
* @example - checkAnagramMap('Eleven plus two', 'Twelve plus one') => true
*/
const checkAnagramMap = (str1, str2) => {
// check that inputs are strings.
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
throw new TypeError('Both arguments should be strings.')
}

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

const str1List = Array.from(str1.toUpperCase()) // str1 to array

// get the occurrences of str1 characters by using HashMap
const str1Occurs = str1List.reduce(
(map, char) => map.set(char, map.get(char) + 1 || 1),
new Map()
)

for (const char of str2.toUpperCase()) {
// if char has not exist to the map it's return false
if (!str1Occurs.has(char)) {
return false
}

let getCharCount = str1Occurs.get(char)
str1Occurs.set(char, --getCharCount)

getCharCount === 0 && str1Occurs.delete(char)
}

return true
const normalize = (str) =>
str.toLowerCase().replace(/\s/g, '').split('').sort().join('')
return normalize(str1) === normalize(str2)
}

export { checkAnagramRegex, checkAnagramMap }
export { checkAnagram }
178 changes: 22 additions & 156 deletions String/test/CheckAnagram.test.js
Original file line number Diff line number Diff line change
@@ -1,177 +1,43 @@
import { checkAnagramMap, checkAnagramRegex } from '../CheckAnagram'
import { checkAnagram } from '../CheckAnagram.js'

describe('Testing checkAnagramRegex', () => {
it.each`
inputOne | inputTwo
${123456} | ${'abcd'}
${[1, 2, 3, 4, 5, 6]} | ${'abcd'}
${{ test: 'test' }} | ${'abcd'}
${'abcd'} | ${123456}
${'abcd'} | ${[1, 2, 3, 4, 5, 6]}
${'abcd'} | ${{ test: 'test' }}
`(
'expects to throw the type Error given values $inputOne and $inputTwo',
({ inputOne, inputTwo }) => {
expect(() => checkAnagramRegex(inputOne, inputTwo)).toThrowError()
}
)

it('expects to return false if the arguments have different lengths', () => {
const SUT = checkAnagramRegex('abs', 'abds')
expect(SUT).toBe(false)
})

it('expects to return false if the arguments are not anagrams', () => {
const SUT = checkAnagramRegex('abcs', 'abds')
expect(SUT).toBe(false)
})

it('expects to return true if the arguments are anagrams', () => {
const SUT = checkAnagramRegex('abcd', 'bcad')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments of length 1 and are the same letter', () => {
const SUT = checkAnagramRegex('a', 'a')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments of are both empty strings', () => {
const SUT = checkAnagramRegex('', '')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments are anagrams with an odd length', () => {
const SUT = checkAnagramRegex('abcde', 'edcab')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments are anagrams with an even length', () => {
const SUT = checkAnagramRegex('abcdef', 'fedcab')
expect(SUT).toBe(true)
})

it('expects to return false if either argument is an empty string while the other is not', () => {
const SUT = checkAnagramRegex('', 'edcab')
expect(SUT).toBe(false)
const SUT2 = checkAnagramRegex('edcab', '')
expect(SUT2).toBe(false)
})

it('expects to return true if the arguments contain the same letters but have unequal case', () => {
const SUT = checkAnagramRegex('ABDCE', 'abcde')
expect(SUT).toBe(true)
const SUT2 = checkAnagramRegex('AbCdE', 'aBCdE')
expect(SUT2).toBe(true)
const SUT3 = checkAnagramRegex('Eleven plus two', 'Twelve plus one')
expect(SUT3).toBe(true)
})

it('expects to return true if the arguments are anagrams and contain number characters', () => {
const SUT = checkAnagramRegex('a1b2', '12ba')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments are anagrams and contain space characters', () => {
const SUT = checkAnagramRegex('a1 b2', '1 2ba')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments are anagrams and contain punctuation characters', () => {
const SUT = checkAnagramRegex('a!1b@2', '1@2ba!')
expect(SUT).toBe(true)
})

it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => {
const SUT = checkAnagramRegex('ea cb', 'e cba')
expect(SUT).toBe(false)
})
})

describe('Testing checkAnagramMap', () => {
it.each`
inputOne | inputTwo
${123456} | ${'abcd'}
${[1, 2, 3, 4, 5, 6]} | ${'abcd'}
${{ test: 'test' }} | ${'abcd'}
${'abcd'} | ${123456}
${'abcd'} | ${[1, 2, 3, 4, 5, 6]}
${'abcd'} | ${{ test: 'test' }}
`(
'expects to throw the type Error given values $inputOne and $inputTwo',
({ inputOne, inputTwo }) => {
expect(() => checkAnagramMap(inputOne, inputTwo)).toThrowError()
}
)

it('expects to return false if the arguments have different lengths', () => {
const SUT = checkAnagramMap('abs', 'abds')
expect(SUT).toBe(false)
})

it('expects to return false if the arguments are not anagrams', () => {
const SUT = checkAnagramMap('abcs', 'abds')
expect(SUT).toBe(false)
})

it('expects to return true if the arguments are anagrams', () => {
const SUT = checkAnagramMap('abcd', 'bcad')
expect(SUT).toBe(true)
})

it('expects to return true if the arguments of length 1 and are the same letter', () => {
const SUT = checkAnagramMap('a', 'a')
expect(SUT).toBe(true)
describe('checkAnagram', () => {
test("'listen' and 'silent' are anagrams", () => {
expect(checkAnagram('listen', 'silent')).toBe(true)
})

it('expects to return true if the arguments of are both empty strings', () => {
const SUT = checkAnagramMap('', '')
expect(SUT).toBe(true)
test("'hello' and 'world' are NOT anagrams", () => {
expect(checkAnagram('hello', 'world')).toBe(false)
})

it('expects to return true if the arguments are anagrams with an odd length', () => {
const SUT = checkAnagramMap('abcde', 'edcab')
expect(SUT).toBe(true)
test("'Astronomer' and 'Moon starer' are anagrams", () => {
expect(checkAnagram('Astronomer', 'Moon starer')).toBe(true)
})

it('expects to return true if the arguments are anagrams with an even length', () => {
const SUT = checkAnagramMap('abcdef', 'fedcab')
expect(SUT).toBe(true)
test("'triangle' and 'integral' are anagrams", () => {
expect(checkAnagram('triangle', 'integral')).toBe(true)
})

it('expects to return false if either argument is an empty string while the other is not', () => {
const SUT = checkAnagramMap('', 'edcab')
expect(SUT).toBe(false)
const SUT2 = checkAnagramMap('edcab', '')
expect(SUT2).toBe(false)
test('empty strings are anagrams', () => {
expect(checkAnagram('', '')).toBe(true)
})

it('expects to return true if the arguments contain the same letters but have unequal case', () => {
const SUT = checkAnagramMap('ABDCE', 'abcde')
expect(SUT).toBe(true)
const SUT2 = checkAnagramMap('AbCdE', 'aBCdE')
expect(SUT2).toBe(true)
const SUT3 = checkAnagramMap('Eleven plus two', 'Twelve plus one')
expect(SUT3).toBe(true)
test('case insensitive check', () => {
expect(checkAnagram('Listen', 'Silent')).toBe(true)
})

it('expects to return true if the arguments are anagrams and contain number characters', () => {
const SUT = checkAnagramMap('a1b2', '12ba')
expect(SUT).toBe(true)
test('different lengths are NOT anagrams', () => {
expect(checkAnagram('abc', 'ab')).toBe(false)
})

it('expects to return true if the arguments are anagrams and contain space characters', () => {
const SUT = checkAnagramMap('a1 b2', '1 2ba')
expect(SUT).toBe(true)
test("'abc' and 'cba' are anagrams", () => {
expect(checkAnagram('abc', 'cba')).toBe(true)
})

it('expects to return true if the arguments are anagrams and contain punctuation characters', () => {
const SUT = checkAnagramMap('a!1b@2', '1@2ba!')
expect(SUT).toBe(true)
test('throws TypeError for non-string first input', () => {
expect(() => checkAnagram(123, 'silent')).toThrow(TypeError)
})

it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => {
const SUT = checkAnagramMap('ea cb', 'e cba')
expect(SUT).toBe(false)
test('throws TypeError for non-string second input', () => {
expect(() => checkAnagram('listen', 123)).toThrow(TypeError)
})
})
Loading