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

Upgrade checkAnagram function & Fixes #902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
raklaptudirm merged 14 commits into TheAlgorithms:master from fahimfaisaal:upgrade-anagram
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
769a388
pref: optimize the algo via reduce & replace method
fahimfaisaal Feb 23, 2022
d0d8bff
feat: add TypeError for invalid types
fahimfaisaal Feb 23, 2022
40ae7b6
test: upgrade test case for invalid types
fahimfaisaal Feb 23, 2022
7c7f8c7
docs: add js doc
fahimfaisaal Feb 24, 2022
db1f261
test: modify the case-sensitive test case
fahimfaisaal Feb 24, 2022
28836df
pref: Optimize algo & add case-insensitive mode
fahimfaisaal Feb 24, 2022
aaeed30
style: format with standard style
fahimfaisaal Feb 24, 2022
0fd4db1
docs: fix the js doc
fahimfaisaal Feb 24, 2022
5d097a5
docs: rename function name & add comments
fahimfaisaal Feb 24, 2022
98a5b2b
feat: add chackAnagramViaMap function
fahimfaisaal Feb 24, 2022
828d2d3
test: add test case for checkAnagramViaMap func
fahimfaisaal Feb 24, 2022
e24f57e
fix: remove **Via** from functions name
fahimfaisaal Feb 24, 2022
423c2c1
style: fix alignment of js doc
fahimfaisaal Feb 24, 2022
87b3a4a
chore: grammar fix
raklaptudirm Feb 25, 2022
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
79 changes: 54 additions & 25 deletions String/CheckAnagram.js
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,47 +1,76 @@
// 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 case sensitive; i.e. Aba and aba is not a anagram.
// inputs are strings i.e. str1 and str2
const checkAnagram = (str1, str2) => {
// 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
*/
const checkAnagramRegex = (str1, str2) => {
// check that inputs are strings.
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
return 'Not string(s)'
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
}

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

const str1CharCount = new Map()
/**
* @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.')
}

for (let i = 0; i < str1.length; i++) {
let previousCount = 0
if (str1CharCount.has(str1[i])) {
previousCount = str1CharCount.get(str1[i])
}
str1CharCount.set(str1[i], previousCount + 1)
// If both strings have not same lengths then they can not be anagram.
if (str1.length !== str2.length) {
return false
}

// Now check if second string has same characters?
const str1List = Array.from(str1.toUpperCase()) // str1 to array

for (let i = 0; i < str2.length; i++) {
let previousCount = 0
// if str1CharCount has no key for str2[i] then not anagram.
if (!str1CharCount.has(str2[i])) return false
// 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()
)

previousCount = str1CharCount.get(str2[i])
str1CharCount.set(str2[i], previousCount - 1)
}
for (const char of str2.toUpperCase()) {
// if char has not exist to the map it's return false
if (!str1Occurs.has(char)) {
return false
}

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

for (const key in str1CharCount) {
if (str1CharCount[key] !== 0) return false
getCharCount === 0 && str1Occurs.delete(char)
}

return true
}

export { checkAnagram }
export { checkAnagramRegex, checkAnagramMap }
135 changes: 114 additions & 21 deletions String/test/CheckAnagram.test.js
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { checkAnagram } from '../CheckAnagram'
import { checkAnagramMap, checkAnagramRegex } from '../CheckAnagram'

describe('checkAnagram', () => {
describe('Testing checkAnagramRegex', () => {
it.each`
inputOne | inputTwo
${123456} | ${'abcd'}
Expand All @@ -10,79 +10,172 @@ describe('checkAnagram', () => {
${'abcd'} | ${[1, 2, 3, 4, 5, 6]}
${'abcd'} | ${{ test: 'test' }}
`(
'expects to return "Not string(s)" given values $inputOne and $inputTwo',
'expects to throw the type Error given values $inputOne and $inputTwo',
({ inputOne, inputTwo }) => {
const SUT = checkAnagram(inputOne, inputTwo)
expect(SUT).toBe('Not string(s)')
expect(
() => checkAnagramRegex(inputOne, inputTwo)
).toThrowError()
}
)

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

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

it('expects to return true if the arguments are anagrams', () => {
const SUT = checkAnagram('abcd', 'bcad')
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 = checkAnagram('a', 'a')
const SUT = checkAnagramRegex('a', 'a')
expect(SUT).toBe(true)
})

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

it('expects to return true if the arguments are anagrams with an odd length', () => {
const SUT = checkAnagram('abcde', 'edcab')
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 = checkAnagram('abcdef', 'fedcab')
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 = checkAnagram('', 'edcab')
const SUT = checkAnagramRegex('', 'edcab')
expect(SUT).toBe(false)
const SUT2 = checkAnagram('edcab', '')
const SUT2 = checkAnagramRegex('edcab', '')
expect(SUT2).toBe(false)
})

it('expects to return false if the arguments contain the same letters but have unequal case', () => {
const SUT = checkAnagram('ABDCE', 'abcde')
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)
const SUT2 = checkAnagram('AbCdE', 'aBCdE')
})
})

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

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

it('expects to return true if the arguments are anagrams with an odd length', () => {
const SUT = checkAnagramMap('abcde', 'edcab')
expect(SUT).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)
})

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

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

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

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

it('expects to return true if the arguments are anagrams and contain punctuation characters', () => {
const SUT = checkAnagram('a!1b@2', '1@2ba!')
const SUT = checkAnagramMap('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 = checkAnagram('ea cb', 'e cba')
const SUT = checkAnagramMap('ea cb', 'e cba')
expect(SUT).toBe(false)
})
})

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