Function that generates all combinations of a string - javascript

I am new to javascript still trying to learn things.
I've found a solution to a problem about a function that should generate all combinations of a characters within a string.
I'm trying to figure out:
What is happening inside the loop?
How does the loops execute step by step?
I cannot figure how it reaches to that final output.
I tried for a long time to figure out but I m not sure what happens inside those
loops. I don't understand tho how it gets "ab", "ac". ... together
in the final output and where arrTemp pushes result[x] and char. I saw that the result array is initially empty, then is concatenated with arrTemp.
Here is the code I'm struggling with:
function combString(str){
var lenStr = str.length;
var result = [];
var indexCurrent = 0;
while(indexCurrent < lenStr){
var char = str.charAt(indexCurrent);
var x;
var arrTemp = [char];
for(x in result) {
arrTemp.push(""+result[x]+char);
}
result = result.concat(arrTemp);
indexCurrent++;
}
return result;
}
console.log(combString("abc"));
And this is the output
["a", "b", "ab", "c", "ac", "bc", "abc"]

We can simply achieve it by using 'Slice'
function combinator (s) {
list_of_strings = new Array();
for(i=0;i<s.length;i++) {
for(j=i+1;j<s.length+1;j++) {
list_of_strings.push(s.slice(i, j));
}
}
return list_of_strings;
}
document.write(combinator("dog"));

ok that's pretty simple frist I will comment the code for you and then I will show what is done with a simple string example:
function combString(str){
var lenStr = str.length;
var result = [];
var indexCurrent = 0;
while(indexCurrent < lenStr){ // repeat until indexCurrent equals lenStr, the aim is to browse threw the string
var char = str.charAt(indexCurrent); // select the char at indexCurrent
var x;
var arrTemp = [char];//put the selected char in an array
for(x in result) {
/*Here it's a little bit tricky, array are object, and actually
the indexes of the array are properties which names are includes between 0 and
2³²-2, but they can have other properties like any other object. that's
the reason why you can use a for in loop here which will go threw the
array and perform action on its properties with property name stored in the x variable (actually it is better to use a foreach loop) */
arrTemp.push(""+result[x]+char); /* so here you concat the
value of the current property of result (in the for in loop) with the char
at indexCurrent and you add the concatenation result at the end of arrTemp */
}
result = result.concat(arrTemp); //here you concat result array and arrTemp and assign the concatenation result to result (I know there is a lot of result ahah)
indexCurrent++; //and then you go to the next char in the string and you repeat
}
// when the while loop ends you return result
return result;
}
so let's see an example with this string "abc":
for indexCurrent =0 :
result = [];
char = 'a';
arrayTemp (before for in loop)= ['a'];
arrayTemp (after for in loop)= ['a'];
result = ['a'];
for indexCurrent =1 :
result = ['a'];
char = 'b';
arrayTemp (before for in loop) = ['b'];
arrayTemp (after for in loop) = ['b','ab']
result = ['a', 'b', 'ab'];
for indexCurrent =2 :
result = ['a', 'b', 'ab'];
char = 'c';
arrayTemp (before for in loop) = ['c'];
arrayTemp (after for in loop) = ['c','ac','bc','abc']
result = ['a', 'b', 'ab','c','ac','bc','abc'];
I hope that helped you

Here is the commented code, hopefully it will help you understand!
function combString(str) {
//String length
var lenStr = str.length;
//Initially empty, where the results will be stored
var result = [];
//Currently selected letter
var indexCurrent = 0;
//Looping from 0 to the length of the string
//var char is selecting the character at this index. Ex: "a", then "b", then "c"
while (indexCurrent < lenStr) {
//Get the character at the index position.
var char = str.charAt(indexCurrent);
var x;
var arrTemp = [char];
//For each previous result
for (x in result) {
//Add the current character to the index
arrTemp.push("" + result[x] + char);
/*
* Ex: "abc"
* First round: result is empty, so this code doesn't execute
* Second round: result contains "a". Adds "ab" to the result array
* - Then. result array will contain "a","b" and "ab"
* Third round: result contains "a","b","ab"
* For all of these results, add "c" to the resulting array
* Ex: "ac","bc", "abc"
* - Then add "c"
*/
}
result = result.concat(arrTemp);
//Increment the current index to go to the next character
indexCurrent++;
}
return result;
}
console.log(combString("abc"));

Let's assume input is "ab". Here's how the function works without the loops:
var str = "ab";
var lenStr = str.length;
var result = [];
var indexCurrent = 0;
var char, x, arrTemp;
//first while iteration begins
//indexCurrent === 0
//so char becomes "a"
char = str.charAt(indexCurrent);
//A temp array is created so it can be concatenated to the results array.
arrTemp = [char];
//arrTemp == ["a"]
//for-loop here, but since the result array is empty, it wont execute
//result becomes ["a"]
result = result.concat(arrTemp);
//indexCurrent becomes 1
indexCurrent++;
//second while iteration begins
//indexCurrent === 1
//so char becomes "b"
char = str.charAt(indexCurrent);
arrTemp = [char];
//arrTemp == ["b"]
//For-loop begins, x === 0
//result[x] is the xth (in this case, first) value of the result-array
//the double quotes cast the result as string
//in other words, it says:
//"store at the end of the array arrTemp, as string, the value from index x
//in the array result, plus the character stored in the variable char"
arrTemp.push(""+result[x]+char);
//arrTemp is now ["b", "ab"]
//result only has one item, so for-loop ends
//result becomes ["a", "b", "ab"]
result = result.concat(arrTemp);
//indexCurrent becomes 2
indexCurrent++;
//function returns result
Do note that for-in loops should not be used for iterating over arrays (see here).

Simple use of for loop and while statement to get different combinations.
function combu(s){
var buff = [];
var res = [];
for (i=0;i<s.length;i++){
buff = [s[i]];
var index=0;
while(res[index]){
buff.push(''+res[index]+s[i]);
index++;
}
res = res.concat(buff);
}
return res;
}
combu('abc');

Related

I need to split an array into N number of arrays based on searching for an element from another array

I need to split an array into N number of arrays based on searching for an element from another array.
consider this scenerio
var test = ["1","2","3","env","6","7","8","uat","2344","wersdf","sdfs"];
var test2=["env","uat"];
now I want a map like
{
env:["6","7","8"],
uat:["2344","wersdf","sdfs"]
}
Note that the array items in test2 and test1 is dynamic.But two test2 values will not be coming one after another in the test array, there will be some items between it.
You could do with Array#Reduce
First iterate the test2 array and match the index of test
Then use the forloop with starting value ind+1 .it will target the next argument of delimiter
After pass the value to array using acc[b].push()
Then detect next delimiter using test2.indexOf(test[i]) == -1 on else condition.That time you need to break the statement.Then again start the second argument of test2
function maper(test, test2) {
return test2.reduce((acc, b) => {
let ind = test.indexOf(b); //detect starting index of delimiter
if (ind > -1) {
acc[b] = acc[b] || [];
for (var i = ind+1; i < test.length; i++) {
if (test2.indexOf(test[i]) == -1) { //detet next delimiter reach
acc[b].push(test[i])
}else{
break;
}
}
}
return acc
}, {})
}
var test = ["1", "2", "3", "env", "6", "7", "8", "uat", "2344", "wersdf", "sdfs"];
var test2 = ["env", "uat"];
console.log(maper(test, test2))
var test = ["1","2","3","env","6","7","8","uat","2344","wersdf","sdfs"];
var test2=["env","uat"];
var indexArray = [];
test2.map(key=>{
var index = test.indexOf(key);
indexArray.push(index);
})
var obj = {};
for(var i = 0; i<indexArray.length; i++){
var part = test.slice(indexArray[i]+1, indexArray[i+1]);
obj = {...obj,[test2[i]]: [ ...part]};
}
console.log("obj = ", obj);

javascript weird console logs

I've got a assignment to make function that gives you a sorted array with 6 random numbers from 1 to 45. None of the array values should equal to one another.
I thought about a solution that would work in Java but the JavaScript console logs I get are pretty confusing. Could anyone help me out?
"use strict";
var numbers = [];
for(var x = 1; x <46;x++){
numbers.push(x);
}
function LottoTipp(){
var result = [];
for(var i = 0; i <6; i++){
var randomNum = Math.round(Math.random()* 45);
var pushed = numbers[randomNum];
result.push(pushed);
numbers.splice(randomNum)
}
return console.log(result) + console.log(numbers);
}
LottoTipp();
the console logs
[ 34, 7, undefined, undefined, undefined, undefined ]
[ 1, 2, 3, 4, 5, 6 ]
There were three problems:
If you want to remove one item of an array you have to splice it by the items index and give a deletecount.
In your case: numbers.splice(randomNum, 1);
You have to use Math.floor instead of Math.round, because Math.floor always down to the nearest integerer, while Math.round searches for the nearest integer wich could be higher than numbers.length.
After removing one item the length of the array has been changed. So you have to multiply by numbers.lenght instead of 45.
In your case: var randomNum = Math.floor(Math.random()* numbers.length);
"use strict";
var numbers = [];
for(var x = 1; x < 46; x++){
numbers.push(x);
}
function LottoTipp(){
var result = [];
for(var i = 0; i < 6; i++){
var randomNum = Math.floor(Math.random()* numbers.length);
var pushed = numbers[randomNum];
result.push(pushed);
numbers.splice(randomNum, 1);
}
return console.log(result) + console.log(numbers);
}
LottoTipp();
If you only want an array with random unique numbers I would suggest doing it like this:
<script>
var array = [];
for(i = 0; i < 6; i++) {
var number = Math.round(Math.random() *45);
if(array.indexOf(number) == -1) { //if number is not already inside the array
array.push(number);
} else { //if number is inside the array, put back the counter by one
i--;
}
}
console.log(array);
</script>
There is no issue with the console statement the issue is that you are modifying the numbers array in your for loop. As you are picking the random number between 1-45 in this statement:-
var randomNum = Math.round(Math.random()* 45);
and you expect that value would be present in the numbers array at that random index. However you are using array.splice() and providing only first parameter to the function. The first parameter is the start index from which you want to start deleting elements, find syntax here. This results in deleting all the next values in the array.Therefore if you pick a random number number say.. 40, value at numbers[40] is undefined as you have deleted contents of the array.
if you want to generate unique set of numbers follow this post.
hope it helps!
Just add the number in the result if it is unique otherwise take out a new number and then sort it. Here is an implementation:
let result = []
while(result.length < 6) {
let num = Math.round(Math.random() * 45);
if(!result.includes(num)) {
result.push(num);
}
}
result.sort((a,b) => {
return parseInt(a) - parseInt(b);
});
console.log(result);

Parse an array of strings into a new array javascript

I want to cycle through an array of strings and split those strings on a certain character, and then feed those new strings into an array, ex. take the string "val: key" from the first array and then use a function to retrieve the string from the array and split it on ":" into a new array that would contain ["val","key"]. This is what I have so far, and at the bottom is what is returning when console.log it.
var dict = [];
dict.push("me; pro: myself");
dict.push("labor, laboris; n: work");
dict.push("voco, vocare, vocavi, vocatum; v: call");
function parseDict(arr){
/* parseDict takes a dictionary entry and splits it between its latin part and its part of speech/english translation*/
var dictFinal = [];
arr.toString();
for (i = 0; i < arr.length; i++){
dictFinal[i] += arr[i].split(";");
}
return dictFinal;
}
console.log(parseDict(dict)) prints out
[ 0: "undefinedme; pro: myself"
1: "undefinedlabor, laboris; n: work"
2: "undefinedvoco, vocare, vocavi, vocatum; v: call"
]
Why is it not splitting into two strings on the ";", and why is it returning an undefined value?
It is undefined because you are doing += to an empty array index
dictFinal[i] += arr[i].split(";");
^^
First pass dictFinal[i] is undefined so it is
dictFinal[i] = undefined + arr[i].split(";");
You probably just want
dictFinal[i] = arr[i].split(";");
Use dictFinal.push(...) or dictFinal[i] = ...
Calling arr.toString(); doesn't do much in your case; it simply makes a string from the array which is then expected to be assigned to an variable / returned etc...
var dict = [];
dict.push("me; pro: myself");
dict.push("labor, laboris; n: work");
dict.push("voco, vocare, vocavi, vocatum; v: call");
function parseDict(dict) {
// considered that you know the final length of the final
// length of the array you could use: new Array(dict.length)
var dictFinal = [];
for (i = 0; i < dict.length; i++) {
dictFinal[i] = dict[i].split(";");
}
return dictFinal;
}
console.log(parseDict(dict)); // [["me"," pro: myself"],["labor, laboris"," n: work"],["voco, vocare, vocavi, vocatum"," v: call"]]
+= will try to get whatever is in the variable and concat / add with whatever is on the right side of the equal sign:
var a = 'abc';
a += 'def';
console.log(a); // abcdef
var b = 1;
b += 1;
console.log(b); // 2
// and your's case:
var c; // here c === undefined (your case dictFinal[i] === undefined)
c += 'ABC';
console.log(c); // undefinedABC
var my_array = [1,2,3];
// .toString() is called on the array so the concatenation can happen:
// It would be the same as writing:
// 'my_string' + my_array.toString();
// or 'my_string' + my_array.join(',');
var d = 'my_string' + my_array;
console.log(d); // my_string1,2,3
if you really need the += and would not want to see the 'UNDEFINED', could try:
dictFinal[i] = ((typeof dictFinal[i]!=='undefined') ? dictFinal[i]+arr[i].split(";") : arr[i].split(";"));

Split string into array by several delimiters

Folks,
I have looked at underscore.string and string.js modules and still can't find a good way to do the following:
Suppose I have a query string string:
"!dogs,cats,horses!cows!fish"
I would like to pass it to a function that looks for all words that start with !, and get back an Array:
['dogs','cows','fish']
Similarly, the same function should return an array of words that start with ,:
['cats','horses]
Thanks!!!
You can use RegEx to easily match the split characters.
var string = "!dogs,cats,horses!cows!fish";
var splitString = string.split(/!|,/);
// ["dogs", "cats", "horses", "cows", "fish"]
The only issue with that is that it will possibly add an empty string at the beginning of the array if you start it with !. You could fix that with a function:
splitString.forEach(function(item){
if(item === ""){
splitString.splice(splitString.indexOf(item), 1)
}
});
EDIT:
In response to your clarificaiton, here is a function that does as you ask. It currently returns an object with the values commas and exclaim, each with an array of the corresponding elements.
JSBin showing it working.
function splitString(str){
var exclaimValues = [];
var expandedValues = [];
var commaValues = [];
var needsUnshift = false;
//First split the comma delimited values
var stringFragments = str.split(',');
//Iterate through them and see if they contain !
for(var i = 0; i < stringFragments.length; i++){
var stringValue = stringFragments[i];
// if the value contains an !, its an exclaimValue
if (stringValue.indexOf('!') !== -1){
exclaimValues.push(stringValue);
}
// otherwise, it's a comma value
else {
commaValues.push(stringValue);
}
}
// iterate through each exclaim value
for(var i = 0; i < exclaimValues.length; i++){
var exclaimValue = exclaimValues[i];
var expandedExclaimValues = exclaimValue.split('!');
//we know that if it doesn't start with !, the
// the first value is actually a comma value. So move it
if(exclaimValue.indexOf('!') !== 0) commaValues.unshift(expandedExclaimValues.shift());
for(var j = 0; j < expandedExclaimValues.length; j++){
var expandedExclaimValue = expandedExclaimValues[j];
//If it's not a blank entry, push it to our results list.
if(expandedExclaimValue !== "") expandedValues.push(expandedExclaimValue);
}
}
return {comma: commaValues, exclaim: expandedValues};
}
So if we do:
var str = "!dogs,cats,horses!cows!fish,comma!exclaim,comma2,comma3!exclaim2";
var results = splitString(str)
results would be:
{
comma: ["comma3", "comma", "horses", "cats", "comma2"],
exclaim: ["dogs", "cows", "fish", "exclaim", "exclaim2"]
}

Combinations of elements of multiple arrays

I have this type of data
var arr = [
["A", "AA"],
["B"],
["C", "CC", "CCC"]
];
I want to get combinations of all the elements within each array. for e.g.
A B
A B C
A B CC
A B CCC
A C
A CC
A CCC
...
AA B CCC
Note the sequence of the words are same, like this should not be one of the combination B A C.
I tried a couple of logics but can't get what I am looking for. I can obtain all permutations and combinations of all the words, but that's not what I am looking for.
Please suggest
You basically want to permute across multiple lists:
function permute(input)
{
var out = [];
(function permute_r(input, current) {
if (input.length === 0) {
out.push(current);
return;
}
var next = input.slice(1);
for (var i = 0, n = input[0].length; i != n; ++i) {
permute_r(next, current.concat([input[0][i]]));
}
}(input, []));
return out;
}
permute(arr);
The problem can be solved recursively. That is: for the first array, you have, for each of the elements, the result of the combinations formed with the two other arrays.
Something like this could work:
function arrayCombine ( array ) {
if (array.length > 1) {
var result = new Array();
//This combines all the arrays except the first
var otherCombs = arrayCombine ( array.slice(1) );
for ( var n = 0; n < array[0].length; n++ )
for ( var i = 0; i < otherCombs.length; i++ )
result.push ( array[0][n] + otherCombs[i] );
return result;
}
//If we have only one array, the result is the array itself, for it contains in itself all the combinations of one element that can be made
else return array[0];
}
Make an array of indices (idx), each element corresponding to each row. Initial value 0.
Start with index i = 0
Do what you do with the current combination.
Increment idx[i]. If it's less than the length of the row, go to 2
Set idx[i] to zero
Increment i. If it's greater than the number of rows, terminate algorithm, otherwise go to 2

Categories

Resources