Split string into an object javascript - javascript

I have this string.
'"pen pineapple" apple pen "pen pen"'
Is there a good way to convert it into an object which would look like this:
{
a: "pen pineapple",
b: "apple",
c: "pen",
d: "pen pen"
}
I am looking for a solution in pure javascript!

Splitting strings that have quotes...
https://stackoverflow.com/a/18647776/2725684
Then converting that array into an object...
https://stackoverflow.com/a/4215753/2725684
So, when you combine these answers, it looks like this...
var myRegexp = /[^\s"]+|"([^"]*)"/gi;
var myString = '"pen pineapple" apple pen "pen pen"';
var myArray = [];
do {
var match = myRegexp.exec(myString);
if (match != null) {
myArray.push(match[1] ? match[1] : match[0]);
}
} while (match != null);
var obj = myArray.reduce(function(acc, cur, i) {
acc[i] = cur;
return acc;
}, {});
console.log(obj);

You could use an adapted version of Split a string by commas but ignore commas within double-quotes using Javascript and use Number#toString method for the keys.
var str = '"pen pineapple" apple pen "pen pen"',
arr = str.match(/(".*?"|[^" \s]+)(?=\s* |\s*$)/g),
object = {};
arr.forEach(function (a, i) {
object[(i + 10).toString(36)] = a.replace(/"/g, '');
})
console.log(object);

This might not be the most efficient function but does what you need (returns array)
function splitter(inputString) {
var splitted = inputString.split(' ');
var out = []
var temp = "";
var quoteStarted = false;
for (i = 0; i < splitted.length; i++) {
if (splitted[i].indexOf('"') > -1 && !quoteStarted) {
temp += splitted[i] + " ";
quoteStarted = true;
} else if (quoteStarted && splitted[i].indexOf('"') == -1) {
temp += splitted[i] + " ";
} else if (quoteStarted && splitted[i].indexOf('"') > -1) {
temp += splitted[i];
out.push(temp);
quoteStarted = false;
temp = "";
} else {
out.push(splitted[i])
}
}
return out;
}

It can be achieved in pure javascript like this way
let str = '"pen pineapple" "apple" "pen" "pen pen"'
let obj = {}
let pattern = /".*?"/g;
let index = ["a","b","c","d","e"]
let i=0
let key
while(current = pattern.exec(str))
{
key = index[i]
obj[key] = current[0].replace('"','')
i++
}
console.log(obj)

Related

Javascript includes and map together [duplicate]

I am supposed to write a program in JavaScript to find all the anagrams within a series of words provided. e.g.:
monk, konm, nkom, bbc, cbb, dell, ledl, llde
The output should be categorised into rows:
1. monk konm, nkom;
2. bbc cbb;
3. dell ledl, llde;
I already sorted them into alphabetical order and put them into an array. i.e.:
kmno kmno bbc bbc dell dell
However I am stuck in comparing and finding the matching anagram within the array.
Any help will be greatly appreciated.
Javascript objects are excellent for this purpose, since they are essentially key/value stores:
// Words to match
var words = ["dell", "ledl", "abc", "cba"];
// The output object
var anagrams = {};
for (var i in words) {
var word = words[i];
// sort the word like you've already described
var sorted = sortWord(word);
// If the key already exists, we just push
// the new word on the the array
if (anagrams[sorted] != null) {
anagrams[sorted].push(word);
}
// Otherwise we create an array with the word
// and insert it into the object
else {
anagrams[sorted] = [ word ];
}
}
// Output result
for (var sorted in anagrams) {
var words = anagrams[sorted];
var sep = ",";
var out = "";
for (var n in words) {
out += sep + words[n];
sep = "";
}
document.writeln(sorted + ": " + out + "<br />");
}
Here is my take:
var input = "monk, konm, bbc, cbb, dell, ledl";
var words = input.split(", ");
for (var i = 0; i < words.length; i++) {
var word = words[i];
var alphabetical = word.split("").sort().join("");
for (var j = 0; j < words.length; j++) {
if (i === j) {
continue;
}
var other = words[j];
if (alphabetical === other.split("").sort().join("")) {
console.log(word + " - " + other + " (" + i + ", " + j + ")");
}
}
}
where the output would be (the word, the match and the index of both):
monk - konm (0, 1)
konm - monk (1, 0)
bbc - cbb (2, 3)
cbb - bbc (3, 2)
dell - ledl (4, 5)
ledl - dell (5, 4)
To get the characters in the in alphabetical order, I used split("") ot get an array, called sort() and used join("") to get a string from the array.
Simple Solution
function anagrams(stringA, stringB) {
return cleanString(stringA) === cleanString(stringB);
}
function cleanString(str) {
return str.replace(/[^\w]/g).toLowerCase().split('').sort().join()
}
anagrams('monk','konm')
If it is anagrams function will return true otherwise false
I worked through a similar question to this today and wanted to share the results of my work. I was focused on just detecting the anagram so processing the list of words was not part of my exercise but this algorithm should provide a highly performant way to detect an anagram between two words.
function anagram(s1, s2){
if (s1.length !== s2.length) {
// not the same length, can't be anagram
return false;
}
if (s1 === s2) {
// same string must be anagram
return true;
}
var c = '',
i = 0,
limit = s1.length,
match = 0,
idx;
while(i < s1.length){
// chomp the next character
c = s1.substr(i++, 1);
// find it in the second string
idx = s2.indexOf(c);
if (idx > -1) {
// found it, add to the match
match++;
// assign the second string to remove the character we just matched
s2 = s2.substr(0, idx) + s2.substr(idx + 1);
} else {
// not found, not the same
return false;
}
}
return match === s1.length;
}
I think technically is can be solved like this:
function anagram(s1, s2){
return s1.split("").sort().join("") === s2.split("").sort().join("");
}
The reason I chose the earlier approach is that it is more performant for larger strings since you don't need to sort either string, convert to an array or loop through the entire string if any possible failure case is detected.
Probably not the most efficient way, but a clear way around using es6
function sortStrChars(str) {
if (!str) {
return;
}
str = str.split('');
str = str.sort();
str = str.join('');
return str;
}
const words = ["dell", "ledl", "abc", "cba", 'boo'];
function getGroupedAnagrams(words) {
const anagrams = {}; // {abc:[abc,cba], dell:[dell, ledl]}
words.forEach((word) => {
const sortedWord = sortStrChars(word);
if (anagrams[sortedWord]) {
return anagrams[sortedWord].push(word);
}
anagrams[sortedWord] = [word];
});
return anagrams;
}
const groupedAnagrams = getGroupedAnagrams(words);
for (const sortedWord in groupedAnagrams) {
console.log(groupedAnagrams[sortedWord].toString());
}
I had this question in an interview. Given an array of words ['cat', 'dog', 'tac', 'god', 'act'], return an array with all the anagrams grouped together. Makes sure the anagrams are unique.
var arr = ['cat', 'dog', 'tac', 'god', 'act'];
var allAnagrams = function(arr) {
var anagrams = {};
arr.forEach(function(str) {
var recurse = function(ana, str) {
if (str === '')
anagrams[ana] = 1;
for (var i = 0; i < str.length; i++)
recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
};
recurse('', str);
});
return Object.keys(anagrams);
}
console.log(allAnagrams(arr));
//["cat", "cta", "act", "atc", "tca", "tac", "dog", "dgo", "odg", "ogd", "gdo", "god"]
Best and simple way to solve is using for loops and traversing it to each string and then store their result in object.
Here is the solution :-
function anagram(str1, str2) {
if (str1.length !== str2.length) {
return false;
}
const result = {};
for (let i=0;i<str1.length;i++) {
let char = str1[i];
result[char] = result[char] ? result[char] += 1 : result[char] = 1;
}
for (let i=0;i<str2.length;i++) {
let char = str2[i];
if (!result[char]) {
return false;
}
else {
result[char] = -1;
}
}
return true;
}
console.log(anagram('ronak','konar'));
I know this is an ancient post...but I just recently got nailed during an interview on this one. So, here is my 'new & improved' answer:
var AnagramStringMiningExample = function () {
/* Author: Dennis Baughn
* This has also been posted at:
* http://stackoverflow.com/questions/909449/anagrams-finder-in-javascript/5642437#5642437
* Free, private members of the closure and anonymous, innner function
* We will be building a hashtable for anagrams found, with the key
* being the alphabetical char sort (see sortCharArray())
* that the anagrams all have in common.
*/
var dHash = {};
var sortCharArray = function(word) {
return word.split("").sort().join("");
};
/* End free, private members for the closure and anonymous, innner function */
/* This goes through the dictionary entries.
* finds the anagrams (if any) for each word,
* and then populates them in the hashtable.
* Everything strictly local gets de-allocated
* so as not to pollute the closure with 'junk DNA'.
*/
(function() {
/* 'dictionary' referring to English dictionary entries. For a real
* English language dictionary, we could be looking at 20,000+ words, so
* an array instead of a string would be needed.
*/
var dictionaryEntries = "buddy,pan,nap,toot,toto,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie,stearin";
/* This could probably be refactored better.
* It creates the actual hashtable entries. */
var populateDictionaryHash = function(keyword, newWord) {
var anagrams = dHash[keyword];
if (anagrams && anagrams.indexOf(newWord) < 0)
dHash[keyword] = (anagrams+','+newWord);
else dHash[keyword] = newWord;
};
var words = dictionaryEntries.split(",");
/* Old School answer, brute force
for (var i = words.length - 1; i >= 0; i--) {
var firstWord = words[i];
var sortedFirst = sortCharArray(firstWord);
for (var k = words.length - 1; k >= 0; k--) {
var secondWord = words[k];
if (i === k) continue;
var sortedSecond = sortCharArray(secondWord);
if (sortedFirst === sortedSecond)
populateDictionaryHash(sortedFirst, secondWord);
}
}/*
/*Better Method for JS, using JS Array.reduce(callback) with scope binding on callback function */
words.reduce(function (prev, cur, index, array) {
var sortedFirst = this.sortCharArray(prev);
var sortedSecond = this.sortCharArray(cur);
if (sortedFirst === sortedSecond) {
var anagrams = this.dHash[sortedFirst];
if (anagrams && anagrams.indexOf(cur) < 0)
this.dHash[sortedFirst] = (anagrams + ',' + cur);
else
this.dHash[sortedFirst] = prev + ','+ cur;
}
return cur;
}.bind(this));
}());
/* return in a nice, tightly-scoped closure the actual function
* to search for any anagrams for searchword provided in args and render results.
*/
return function(searchWord) {
var keyToSearch = sortCharArray(searchWord);
document.writeln('<p>');
if (dHash.hasOwnProperty(keyToSearch)) {
var anagrams = dHash[keyToSearch];
document.writeln(searchWord + ' is part of a collection of '+anagrams.split(',').length+' anagrams: ' + anagrams+'.');
} else document.writeln(searchWord + ' does not have anagrams.');
document.writeln('<\/p>');
};
};
Here is how it executes:
var checkForAnagrams = new AnagramStringMiningExample();
checkForAnagrams('toot');
checkForAnagrams('pan');
checkForAnagrams('retinas');
checkForAnagrams('buddy');
Here is the output of the above:
toot is part of a collection of 2
anagrams: toto,toot.
pan is part of a collection of 2
anagrams: nap,pan.
retinas is part of a collection of 14
anagrams:
stearin,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie.
buddy does not have anagrams.
My solution to this old post:
// Words to match
var words = ["dell", "ledl", "abc", "cba"],
map = {};
//Normalize all the words
var normalizedWords = words.map( function( word ){
return word.split('').sort().join('');
});
//Create a map: normalizedWord -> real word(s)
normalizedWords.forEach( function ( normalizedWord, index){
map[normalizedWord] = map[normalizedWord] || [];
map[normalizedWord].push( words[index] );
});
//All entries in the map with an array with size > 1 are anagrams
Object.keys( map ).forEach( function( normalizedWord , index ){
var combinations = map[normalizedWord];
if( combinations.length > 1 ){
console.log( index + ". " + combinations.join(' ') );
}
});
Basically I normalize every word by sorting its characters so stackoverflow would be acefkloorstvw, build a map between normalized words and the original words, determine which normalized word has more than 1 word attached to it -> That's an anagram.
Maybe this?
function anagram (array) {
var organized = {};
for (var i = 0; i < array.length; i++) {
var word = array[i].split('').sort().join('');
if (!organized.hasOwnProperty(word)) {
organized[word] = [];
}
organized[word].push(array[i]);
}
return organized;
}
anagram(['kmno', 'okmn', 'omkn', 'dell', 'ledl', 'ok', 'ko']) // Example
It'd return something like
{
dell: ['dell', 'ledl'],
kmno: ['kmno', okmn', 'omkn'],
ko: ['ok', ko']
}
It's a simple version of what you wanted and certainly it could be improved avoiding duplicates for example.
My two cents.
This approach uses XOR on each character in both words. If the result is 0, then you have an anagram. This solution assumes case sensitivity.
let first = ['Sower', 'dad', 'drown', 'elbow']
let second = ['Swore', 'add', 'down', 'below']
// XOR all characters in both words
function isAnagram(first, second) {
// Word lengths must be equal for anagram to exist
if (first.length !== second.length) {
return false
}
let a = first.charCodeAt(0) ^ second.charCodeAt(0)
for (let i = 1; i < first.length; i++) {
a ^= first.charCodeAt(i) ^ second.charCodeAt(i)
}
// If a is 0 then both words have exact matching characters
return a ? false : true
}
// Check each pair of words for anagram match
for (let i = 0; i < first.length; i++) {
if (isAnagram(first[i], second[i])) {
console.log(`'${first[i]}' and '${second[i]}' are anagrams`)
} else {
console.log(`'${first[i]}' and '${second[i]}' are NOT anagrams`)
}
}
function isAnagram(str1, str2) {
var str1 = str1.toLowerCase();
var str2 = str2.toLowerCase();
if (str1 === str2)
return true;
var dict = {};
for(var i = 0; i < str1.length; i++) {
if (dict[str1[i]])
dict[str1[i]] = dict[str1[i]] + 1;
else
dict[str1[i]] = 1;
}
for(var j = 0; j < str2.length; j++) {
if (dict[str2[j]])
dict[str2[j]] = dict[str2[j]] - 1;
else
dict[str2[j]] = 1;
}
for (var key in dict) {
if (dict[key] !== 0)
return false;
}
return true;
}
console.log(isAnagram("hello", "olleh"));
I have an easy example
function isAnagram(strFirst, strSecond) {
if(strFirst.length != strSecond.length)
return false;
var tempString1 = strFirst.toLowerCase();
var tempString2 = strSecond.toLowerCase();
var matched = true ;
var cnt = 0;
while(tempString1.length){
if(tempString2.length < 1)
break;
if(tempString2.indexOf(tempString1[cnt]) > -1 )
tempString2 = tempString2.replace(tempString1[cnt],'');
else
return false;
cnt++;
}
return matched ;
}
Calling function will be isAnagram("Army",Mary);
Function will return true or false
let words = ["dell", "ledl","del", "abc", "cba", 'boo'];
//sort each item
function sortArray(data){
var r=data.split('').sort().join().replace(/,/g,'');
return r;
}
var groupObject={};
words.forEach((item)=>{
let sorteditem=sortArray(item);
//Check current item is in the groupObject or not.
//If not then add it as an array
//else push it to the object property
if(groupObject[sorteditem])
return groupObject[sorteditem].push(item);
groupObject[sorteditem]=[sorteditem];
});
//to print the result
for(i=0;i<Object.keys(groupObject).length;i++)
document.write(groupObject[Object.keys(groupObject)[i]] + "<br>");
/* groupObject value:
abc: (2) ["abc", "cba"]
boo: ["boo"]
del: ["del"]
dell: (2) ["dell", "ledl"]
OUTPUT:
------
dell,ledl
del
abc,cba
boo
*/
Compare string length, if not equal, return false
Create character Hashmap which stores count of character in strA e.g. Hello --> {H: 1, e: 1, l: 2, o: 1}
Loop over the second string and lookup the current character in Hashmap. If not exist, return false, else decrement the value by 1
If none of the above return falsy, it must be an anagram
Time complexity: O(n)
function isAnagram(strA: string, strB: string): boolean {
const strALength = strA.length;
const strBLength = strB.length;
const charMap = new Map<string, number>();
if (strALength !== strBLength) {
return false;
}
for (let i = 0; i < strALength; i += 1) {
const current = strA[i];
charMap.set(current, (charMap.get(current) || 0) + 1);
}
for (let i = 0; i < strBLength; i += 1) {
const current = strB[i];
if (!charMap.get(current)) {
return false;
}
charMap.set(current, charMap.get(current) - 1);
}
return true;
}
function findAnagram(str1, str2) {
let mappedstr1 = {}, mappedstr2 = {};
for (let item of str1) {
mappedstr1[item] = (mappedstr1[item] || 0) + 1;
}
for (let item2 of str2) {
mappedstr2[item2] = (mappedstr2[item2] || 0) + 1;
}
for (let key in mappedstr1) {
if (!mappedstr2[key]) {
return false;
}
if (mappedstr1[key] !== mappedstr2[key]) {
return false;
}
}
return true;
}
console.log(findAnagram("hello", "hlleo"));
Another example only for comparing 2 strings for an anagram.
function anagram(str1, str2) {
if (str1.length !== str2.length) {
return false;
} else {
if (
str1.toLowerCase().split("").sort().join("") ===
str2.toLowerCase().split("").sort().join("")
) {
return "Anagram";
} else {
return "Not Anagram";
}
}
}
console.log(anagram("hello", "olleh"));
console.log(anagram("ronak", "konar"));
const str1 ="1123451"
const str2 = "2341151"
function anagram(str1,str2) {
let count = 0;
if (str1.length!==str2.length) { return false;}
for(i1=0;i1<str1.length; i1++) {
for (i2=0;i2<str2.length; i2++) {
if (str1[i1]===str2[i2]){
count++;
break;
}
}
}
if (count===str1.length) { return true}
}
anagram(str1,str2)
Another solution for isAnagram using reduce
const checkAnagram = (orig, test) => {
return orig.length === test.length
&& orig.split('').reduce(
(acc, item) => {
let index = acc.indexOf(item);
if (index >= 0) {
acc.splice(index, 1);
return acc;
}
throw new Error('Not an anagram');
},
test.split('')
).length === 0;
};
const isAnagram = (tester, orig, test) => {
try {
return tester(orig, test);
} catch (e) {
return false;
}
}
console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '475846'));
var check=true;
var str="cleartrip";
var str1="tripclear";
if(str.length!=str1.length){
console.log("Not an anagram");
check=false;
}
console.log(str.split("").sort());
console.log("----------"+str.split("").sort().join(''));
if(check){
if((str.split("").sort().join(''))===((str1.split("").sort().join('')))){
console.log("Anagram")
}
else{
console.log("not a anagram");
}
}
Here is my solution which addresses a test case where the input strings which are not anagrams, can be removed from the output. Hence the output contains only the anagram strings. Hope this is helpful.
/**
* Anagram Finder
* #params {array} wordArray
* #return {object}
*/
function filterAnagram(wordArray) {
let outHash = {};
for ([index, word] of wordArray.entries()) {
let w = word.split("").sort().join("");
outHash[w] = !outHash[w] ? [word] : outHash[w].concat(word);
}
let filteredObject = Object.keys(outHash).reduce(function(r, e) {
if (Object.values(outHash).filter(v => v.length > 1).includes(outHash[e])) r[e] = outHash[e]
return r;
}, {});
return filteredObject;
}
console.log(filterAnagram(['monk', 'yzx','konm', 'aaa', 'ledl', 'bbc', 'cbb', 'dell', 'onkm']));
i have recently faced this in the coding interview, here is my solution.
function group_anagrams(arr) {
let sortedArr = arr.map(item => item.split('').sort().join(''));
let setArr = new Set(sortedArr);
let reducedObj = {};
for (let setItem of setArr) {
let indexArr = sortedArr.reduce((acc, cur, index) => {
if (setItem === cur) {
acc.push(index);
}
return acc;
}, []);
reducedObj[setItem] = indexArr;
}
let finalArr = [];
for (let reduceItem in reducedObj) {
finalArr.push(reducedObj[reduceItem].map(item => arr[item]));
}
return finalArr;
}
group_anagrams(['car','cra','rca', 'cheese','ab','ba']);
output will be like
[
["car", "cra", "rca"],
["cheese"],
["ab", "ba"]
]
My solution has more code, but it avoids using .sort(), so I think this solution has less time complexity. Instead it makes a hash out of every word and compares the hashes:
const wordToHash = word => {
const hash = {};
// Make all lower case and remove spaces
[...word.toLowerCase().replace(/ /g, '')].forEach(letter => hash[letter] ? hash[letter] += 1 : hash[letter] = 1);
return hash;
}
const hashesEqual = (obj1, obj2) => {
const keys1 = Object.keys(obj1), keys2 = Object.keys(obj2);
let match = true;
if(keys1.length !== keys2.length) return false;
for(const key in keys1) { if(obj1[key] !== obj2[key]) match = false; break; }
return match;
}
const checkAnagrams = (word1, word2) => {
const hash1 = wordToHash(word1), hash2 = wordToHash(word2);
return hashesEqual(hash1, hash2);
}
console.log( checkAnagrams("Dormitory", "Dirty room") );
/*This is good option since
logic is easy,
deals with duplicate data,
Code to check anagram in an array,
shows results in appropriate manner,
function check can be separately used for comparing string in this regards with all benefits mentioned above.
*/
var words = ["deuoll", "ellduo", "abc","dcr","frt", "bu","cba","aadl","bca","elduo","bac","acb","ub","eldou","ellduo","ert","tre"];
var counter=1;
var ele=[];
function check(str1,str2)
{
if(str2=="")
return false;
if(str1.length!=str2.length)
return false;
var r1=[...(new Set (str1.split('').sort()))];
var r2=[...(new Set (str2.split('').sort()))];
var flag=true;
r1.forEach((item,index)=>
{
if(r2.indexOf(item)!=index)
{ flag=false;}
});
return flag;
}
var anagram=function ()
{
for(var i=0;i<words.length && counter!=words.length ;i++)
{
if(words[i]!="")
{
document.write("<br>"+words[i]+":");
counter++;
}
for(var j=i+1;j<words.length && counter !=words.length+1;j++)
{
if(check(words[i],words[j]))
{
ele=words[j];
document.write(words[j]+"&nbsp");
words[j]="";
counter++;
}
}
}
}
anagram();
If you just need count of anagrams
const removeDuplicatesAndSort = [...new Set(yourString.split(', '))].map(word => word.split('').sort().join())
const numberOfAnagrams = removeDuplicatesAndSort.length - [...new Set(removeDuplicatesAndSort)].length
function isAnagram(str1, str2){
let count = 0;
if (str1.length !== str2.length) {
return false;
} else {
let val1 = str1.toLowerCase().split("").sort();
let val2 = str2.toLowerCase().split("").sort();
for (let i = 0; i < val2.length; i++) {
if (val1[i] === val2[i]) {
count++;
}
}
if (count == str1.length) {
return true;
}
}
return false;
}
console.log(isAnagram("cristian", "Cristina"))
function findAnagrams (str, arr){
let newStr = "";
let output = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
for (let k = 0; k < str.length; k++) {
if (str[k] === arr[i][j] && str.length === arr[i].length) {
newStr += arr[i][j];
}
}
} if(newStr.length === str.length){
output.push(newStr);
newStr = "";
}
}
return output;
}
const getAnagrams = (...args) => {
const anagrams = {};
args.forEach((arg) => {
const letters = arg.split("").sort().join("");
if (anagrams[letters]) {
anagrams[letters].push(arg);
} else {
anagrams[letters] = [arg];
}
});
return Object.values(anagrams);
}
function isAnagaram(str1, str2){
if(str1.length!== str2.length){
return false;
}
var obj1 = {};
var obj2 = {};
for(var arg of str1){
obj1[arg] = (obj1[arg] || 0 ) + 1 ;
}
for(var arg of str2){
obj2[arg] = (obj2[arg] || 0 ) + 1 ;
}
for( var key in obj1){
if(obj1[key] !== obj2[key]){
return false;
}
}
return true;
}
console.log(isAnagaram('texttwisttime' , 'timetwisttext'));
let validAnagram = (firstString, secondString) => {
if (firstString.length !== secondString.length) {
return false;
}
let secondStringArr = secondString.split('');
for (var char of firstString) {
charIndexInSecondString = secondString.indexOf(char);
if (charIndexInSecondString === -1) {
return false;
}
secondString = secondString.replace(char, '');
}
return true;
}

Determine groups in a string

I am trying to determine groups in a string.
For example "AAABBCCCCD" should have ["AAA", "BB", "CCCC", "D"] as groups based on the pattern in the string.
Here is my simple function to do that:
const patternGroup = (str) => {
let cursor = str[0]
let groups = []
let currentGroup = ""
for (let i = 0; i < str.length; i++) {
let ch = str[i]
if (ch === cursor) {
currentGroup += ch
}
else {
groups.push(currentGroup)
currentGroup = ch
cursor = ch
}
}
if (currentGroup !== "") {
groups.push(currentGroup)
}
return groups
}
It works as intented but I am looking for a simpler function, maybe using map/reduce or regex. Any ideas?
you can simply use RegExp:
var input = "AAABBCCCCD";
const res = input.match(/([^])(\1*)/g);
console.log(res)
Similar to your implementation:
const patternGroupWithReduce = (str) => {
let currentGroup = ""
return str.split("").reduce((acc, cur, i) => {
currentGroup += cur
if (str[i + 1] !== cur) {
acc.push(currentGroup)
currentGroup = ""
}
return acc
}, [])
}
const patternGroupWithRegex = (str) => {
return str.match(/(.)\1*/g)
}
RegEx /(.)\1/g* uses the back reference for the capturing group.
\1* matches the same char as recently captured one as many times as possible.
Here is the visualization for it:
You could use
(.)\1*
As in:
let string = "AAABBCCCCD";
let rx = /(.)\1*/g;
let parts = string.match(rx);
console.log(parts);
See a demo for the expression on regex101.com.

Count the number of unique occurrences in an array that contain a specific string with Javascript

Here is my javascript array:
arr = ['blue-dots', 'blue', 'red-dots', 'orange-dots', 'blue-dots'];
With Javascript, how can I count the total number of all unique values in the array that contain the string “dots”. So, for the above array the answer would be 3 (blue-dots, orange-dots, and red-dots).
var count = 0,
arr1 = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i].indexOf('dots') !== -1) {
if (arr1.indexOf(arr[i]) === -1) {
count++;
arr1.push(arr[i]);
}
}
}
you check if a certain element contains 'dots', and if it does, you check if it is already in arr1, if not increment count and add element to arr1.
One way is to store element as key of an object, then get the count of the keys:
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
console.log(Object.keys(arr.reduce(function(o, x) {
if (x.indexOf('dots') != -1) {
o[x] = true;
}
return o
}, {})).length)
Try this something like this:
// Create a custom function
function countDots(array) {
var count = 0;
// Get and store each value, so they are not repeated if present.
var uniq_array = [];
array.forEach(function(value) {
if(uniq_array.indexOf(value) == -1) {
uniq_array.push(value);
// Add one to count if 'dots' word is present.
if(value.indexOf('dots') != -1) {
count += 1;
}
}
});
return count;
}
// This will print '3' on console
console.log( countDots(['blue-dots', 'blue', 'red-dots', 'orange-dots', 'blue-dots']) );
From this question, I got the getUnique function.
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
then you can add a function that counts ocurrences of a string inside an array of strings:
function getOcurrencesInStrings(targetString, arrayOfStrings){
var ocurrencesCount = 0;
for(var i = 0, arrayOfStrings.length; i++){
if(arrayOfStrings[i].indexOf(targetString) > -1){
ocurrencesCount++;
}
}
return ocurrencesCount;
}
then you just:
getOcurrencesInStrings('dots', initialArray.getUnique())
This will return the number you want.
It's not the smallest piece of code, but It's highly reusable.
var uniqueHolder = {};
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
arr.filter(function(item) {
return item.indexOf('dots') > -1;
})
.forEach(function(item) {
uniqueHolder[item] ? void(0) : uniqueHolder[item] = true;
});
console.log('Count: ' + Object.keys(uniqueHolder).length);
console.log('Values: ' + Object.keys(uniqueHolder));
Try this code,
arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
sample = [];
for (var i = 0; i < arr.length; i++) {
if ((arr[i].indexOf('dots') !== -1) && (sample.indexOf(arr[i]) === -1)){
sample.push(arr[i]);
}
}
alert(sample.length);
var arr = [ "blue-dots", "blue", "red-dots", "orange-dots", "blue-dots" ];
var fArr = []; // Empty array, which could replace arr after the filtering is done.
arr.forEach( function( v ) {
v.indexOf( "dots" ) > -1 && fArr.indexOf( v ) === -1 ? fArr.push( v ) : null;
// Filter if "dots" is in the string, and not already in the other array.
});
// Code for displaying result on page, not necessary to filter arr
document.querySelector( ".before" ).innerHTML = arr.join( ", " );
document.querySelector( ".after" ).innerHTML = fArr.join( ", " );
Before:
<pre class="before">
</pre>
After:
<pre class="after">
</pre>
To put this simply, it will loop through the array, and if dots is in the string, AND it doesn't already exist in fArr, it'll push it into fArr, otherwise it'll do nothing.
I'd separate the operations of string comparison and returning unique items, to make your code easier to test, read, and reuse.
var unique = function(a){
return a.length === 0 ? [] : [a[0]].concat(unique(a.filter(function(x){
return x !== a[0];
})));
};
var has = function(x){
return function(y){
return y.indexOf(x) !== -1;
};
};
var arr = ["blue-dots", "blue", "red-dots", "orange-dots", "blue-dots"];
var uniquedots = unique(arr.filter(has('dots')));
console.log(uniquedots);
console.log(uniquedots.length);

how to cut a string in javascript

I'm receiving a String like this:
"45,21,555,64,94,796,488,\n " the \n means new line
is there a way to cut the string based on "," and getting only the "number".
I could do it C but how can I search for a character in JavaScript.
thanks for any hint
var parts = "45,21,555,64,94,796,488,\n ".split(',').filter(function(val) {
var num = parseInt(val, 10);
return !isNaN(num) && toString.call(num) === '[object Number]';
});
// parts: ["45", "21", "555", "64", "94", "796", "488"]
This is taking your String and splitting it into an Array based on a delimiter (',') and then running it through a filter function to remove anything that does not evaluate to a valid Number.
See String.prototype.split and Array.prototype.filter.
If you actually want to then convert those values to Numbers, you could chain a map call:
var parts = "45,21,555,64,94,796,488,\n ".split(',')
.filter(function(val) {
var num = parseInt(val, 10);
return !isNaN(num) && toString.call(num) === '[object Number]';
})
.map(function(val) {
return parseInt(val, 10);
});
// parts: [45, 21, 555, 64, 94, 796, 488]
Yes, like this:
var myString = "45,21,555,64,94,796,488,\n ";
var splitStrings = string.split(",");
console.log(splitStrings); //Should log an array to the console, containing only your strings e.g. [45,21,555,64,94,796,488,\n]
This returns an array of strings, split by the character you passed in. You can read more on this method here: http://www.w3schools.com/jsref/jsref_split.asp
After that, you can parse your array to remove anything you don't want like the new line character, or use a filter method to do it inline as detailed in another answer
You can use string.split(splitChar) to split. Then you can use .map or .filter to convert items to number.
var str = "45,21,555,64,94,796,488,\n ";
var arr = str.split(",");
document.write("Array: <pre>"+JSON.stringify(arr)+"</pre>");
var nums = arr.map(function(item){
return parseInt(item);
});
document.write("Numbers: <pre>"+JSON.stringify(nums)+"</pre>");
If you are wanting just the numbers as an array you could do this.
var str = "45,21,555,64,94,796,488,\n ";
var arr = str.split(","); //Make the string into an array
var len = arr.length;
for(var i=0;i<len;i++)
{
try
{
arr[i] = parseInt(arr[i]); // convert the numbers to ints
}
catch(e)
{
arr[i] = null;
}
}
As the fact that strings are just arrays, you can do it this way (a bit more comprehensive, in my opinion):
function noCommas(a)
{
var b = '';
for (var i = 0; i < a.length; i++)
{
if (a[i] != ',') //&& a[i]!= String.fromCharCode(10)) If you want no new lines too
{
b += a[i];
} else
{
//break; -> In case you only want the first value
}
}
return parseInt(b); //To return the value as an integer
}
noCommas('1234,6789'); // returns 12346789
I missunderstood the question, so here's my fixed code:
function noCommas(a)
{
var b = [];
var tempNum = '';
for (var i = 0; i < a.length; i++)
{
if (a[i] != ',' && i != a.length - 1)
{
tempNum += a[i];
} else
{
b.push(parseInt(tempNum))
tempNum = '';
}
}
return b;
}
now if you do noCommas('123,345,324234')[2] it would return 324234.

Construct array from flattened string in JavaScript

JSFiddle: http://jsfiddle.net/3WdzL/1/
I need to convert locale JS object files to flattened versions and back again:
Orig locale object:
var localeObj = {
toolbar: {
link: {
back: 'Back',
menu: 'Menu',
},
flatTest: 'something'
},
countries: [
["AF", "Afghanistan"],
["AX", "Åland Islands"],
['nested', [1, 2, 3, 4]],
["AL", "Albania"]
]
};
Using the following function:
function flattenObj(obj) {
var flattenedObj = {};
var walk = function(obj, stringMap) {
for(k in obj) {
var computedKey = stringMap + (stringMap ? '.' + k : k);
if(typeof obj[k] !== 'object') {
flattenedObj[computedKey] = obj[k];
} else {
walk(obj[k], computedKey);
}
}
};
walk(obj, '');
return flattenedObj;
}
Would produce a flattened object:
{
toolbar.link.back: Back
toolbar.link.menu: Menu
toolbar.flatTest: something
countries.0.0: AF
countries.0.1: Afghanistan
countries.1.0: AX
countries.1.1: Åland Islands
countries.2.0: nested
countries.2.1.0: 1
countries.2.1.1: 2
countries.2.1.2: 3
countries.2.1.3: 4
countries.3.0: AL
countries.3.1: Albania
}
Converting back with the following func works fine for objects:
function deepenObj(obj) {
var deepenedObj = {}, tmp, parts, part;
for (var k in obj) {
tmp = deepenedObj;
parts = k.split('.');
var computedKey = parts.pop();
while (parts.length) {
part = parts.shift();
tmp = tmp[part] = tmp[part] || {};
}
tmp[computedKey] = obj[k];
}
return deepenedObj;
}
But produces a structure like this for the arrays:
region: {
country: {
0: {
0: 'AF',
1: 'Afghanistan'
},
...
2: {
0: 'nested',
1: {
0: 1,
1: 2,
3: 4,
4: 5
}
}
}
}
Obviously this isn't the desired results for the arrays and I haven't been able to come up with a safe, elegant or even working solution yet. PS I am happy to save the arrays to strings differently if it makes converting back easier. Thanks!
You should either keep track if an object is actually an array:
var walk = function(obj, stringMap) {
if (Array.isArray(obj) {
for (var k = 0; k < obj.length; k++)
var computedKey = stringMap ? stringMap + ',' + k : k;
} else {
for (var k in obj) {
var computedKey = stringMap ? stringMap + '.' + k : k;
...
Then, when deepening:
for (var k in obj) {
tmp = deepenedObj;
parts = ["."].concat(k.split(/([\.,])/));
var computedKey = parts.pop(), sign;
while (parts.length) {
sign = parts.shift();
part = !parts.length ? computedKey : parts.shift();
tmp = tmp[part] = tmp[part] || (sign === "," ? [] : {});
}
tmp[computedKey] = obj[k];
}
Note that Array.isArray could be undefined. You can use obj instanceof Array instead.
This solution works if localeObj is an object literal and not an array, because the first point/comma isn't saved in the computed key. You can modify the function if you need to.
The trick here is to use an unusual behaviour of split that pushes captured groups in the splitted array when used with regular expressions, so before every key part there's the proper separator.
Use JSON.stringify() and JSON.parse():
var flattenedObj = JSON.stringify(localeObj);
vat deepenedObj = JSON.parse(flattenedObj);
Demo

Categories