javascript string algorithm - javascript

Let's say I have a string variable called myString, and another string variable called myChar.
var myString = "batuhan"; // it's user input.
var myChar = "0"; // will be one character, always
What I need is, a function that returns all the combinations of myString and myChar.
Like:
"batuhan","batuha0n","batuh0an","batuh0a0n","batu0han","batu0ha0n","batu0h0an","batu0h0a0n","bat0uhan","bat0uha0n","bat0uh0an","bat0uh0a0n","bat0u0han","bat0u0ha0n","bat0u0h0an","bat0u0h0a0n","ba0tuhan","ba0tuha0n","ba0tuh0an","ba0tuh0a0n","ba0tu0han","ba0tu0ha0n","ba0tu0h0an","ba0tu0h0a0n","ba0t0uhan","ba0t0uha0n","ba0t0uh0an","ba0t0uh0a0n","ba0t0u0han","ba0t0u0ha0n","ba0t0u0h0an","ba0t0u0h0a0n","b0atuhan","b0atuha0n","b0atuh0an","b0atuh0a0n","b0atu0han","b0atu0ha0n","b0atu0h0an","b0atu0h0a0n","b0at0uhan","b0at0uha0n","b0at0uh0an","b0at0uh0a0n","b0at0u0han","b0at0u0ha0n","b0at0u0h0an","b0at0u0h0a0n","b0a0tuhan","b0a0tuha0n","b0a0tuh0an","b0a0tuh0a0n","b0a0tu0han","b0a0tu0ha0n","b0a0tu0h0an","b0a0tu0h0a0n","b0a0t0uhan","b0a0t0uha0n","b0a0t0uh0an","b0a0t0uh0a0n","b0a0t0u0han","b0a0t0u0ha0n","b0a0t0u0h0an","b0a0t0u0h0a0n"
Rules: myChar shouldn't follow myChar
How can I do that? Really my brain dead right now :/

It's possible to implement what you want using recursion.
// Example: allCombinations("abcd", "0") returns the array
// ["abcd", "abc0d", "ab0cd", "ab0c0d", "a0bcd", "a0bc0d", "a0b0cd", "a0b0c0d"]
function allCombinations(str, chr) {
if (str.length == 1)
return [str];
var arr = allCombinations(str.substring(1), chr);
var result = [];
var c = str.charAt(0);
for (var i = 0; i < arr.length; i++)
result.push(c + arr[i]);
for (var i = 0; i < arr.length; i++)
result.push(c + chr + arr[i]);
return result;
}

You may or may not have noticed this but this is basically counting in binary. If we define bit 0 to be the absence of myChar and bit 1 to be the presence of myChar, then the following sequence:
var myString = ".....";
var myChar = "1";
var sequence = [
".....1",
"....1.",
"....1.1",
"...1.."
];
is basically counting from 1 to 4 in binary:
var sequence = [
0b0000001,
0b0000010,
0b0000011,
0b0000100
];
Therefore, all you need is a for loop to count up to the bit amount of the length of the string plus 1 (because the position at the end of the string is also legal):
var len = Math.pow(2,myString.length+1);
for (var x = 0; x < len; x++) {
// x in binary is all the possible combinations
// now use the "1" bits in x to modify the string:
// Convert myString to array for easy processing:
var arr = myString.split('');
arr.push(""); // last position;
for (var i = myString.length; i >= 0; i--) {
if ((x >> i) & 0x01) { // check if bit at position i is 1
arr[i] = myChar + arr[i];
}
}
console.log(arr.join('')); // print out one combination
}
Of course, this works only for small strings of up to 31 characters. For larger strings you'd need to do the binary counting using things other than numbers. Doing it in a string form is one option. Another option is to use a bigint library such as BigInteger.js to do the counting.

Related

How to make element in Array change its' place

I'm beginner in JS. I've tried to understand Caesar Cipher ROT13, but it was too complicated for me. So I've tried to write my own code. Here it is below:
function encrip() {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var str = "Ni Hao";
var string = str.toUpperCase();
for (var i = 0; i < string.length; i++) {
for (var k = 0; k < alphabet.length; k++) {
if(string.charAt(i) == alphabet[k]) {
/* console.log(string.charAt(i) + ' ' + alphabet.indexOf(alphabet[k])); */
}
}
}
}
encrip();
But I am stuck. How to do:
1. Get value from var str and then access to var alphabet , after change each letter from var str value to next 3 from alphabet (var str each element's current position would be changed) For example: Input: Ni Hao ==> output: QL KDR
2. Create universal code, I mean, not only for changing position by 3, but when I give value '5', each element would be changed by next 5 positions from alphabet. So output can be changed when I change its' value
I hope I explained everything clearly. Thanks everyone in advance for help!!
you can use the following function to encrypt english words, the 1st parameter is the string to encrypt and the 2nd for shifting
function encryp(str,pos){
var alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var strUC=str.toUpperCase();
var enc="";
for(var i=0;i<strUC.length;i++){
if(strUC.charAt(i)!=" "){
enc+=alpha.charAt((alpha.indexOf(strUC.charAt(i))+pos)%26)
}
else{
enc+=" "
}
// in your case pos=3
}
return enc;
}
console.log(encryp("NiHao",3));
You don't need two for loops to do this. Iterate over the input string and find the index of each character in the alphabet array, if found add the shift to it to get the encrypted character.
To handle overflow use the modulus operator to cycle through the array.
Also I assume that you are not going use any special symbols to do the encryption.
function encrip(string, shift) {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
string = string.toUpperCase();
let arr = [];
for (var i = 0; i < string.length; i++) {
let char = alphabet.indexOf(string[i]) !== -1 ? alphabet[(alphabet.indexOf(string[i]) %26) + shift] : " ";
arr.push(char);
}
let encryp = arr.join("");
console.log(encryp);
return encryp;
}
encrip("Ni Hao", 3);
First of all, instead of your inner for loop scanning the whole alphabet array, you can use the built-in function indexOf:
alphabet.indexOf('K') // returns 10
Secondly, you'll want to build up your enciphered string in a separate variable. For each letter, get the index of that letter in the alphabet, add your cipher offset parameter to that index and add the resulting letter from the alphabet to your new string. An important step is that when you add to the index of the letter, you want to make sure the resulting index is within range for the alphabet array. You can do that using the % (modulo) operator, which will wrap high values back round to the start of the array. In full:
function encipher(input, offset) {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var str = input.toUpperCase();
var result = '';
for (var i = 0; i < str.length; i++) {
letterIndex = alphabet.indexOf(str.charAt(i));
if (letterIndex === -1) {
result += str[i]; // if the letter isn't found in the alphabet, add it to the result unchanged
continue;
}
cipheredIndex = (letterIndex + offset) % alphabet.length; // wrap index to length of alphabet
result += alphabet[cipheredIndex];
}
console.log(result);
}
encipher('Ni Hao', 5); // output: 'SN MFT'

How can I make my output appear all on one line with no spaces?

I have a simple Javascript problem that I'm working on, where the point is to...
Take an input, like 123
Separate the input as single digits, then square those single digits, thus getting 149.
Display that "149" (in this case) as an output.
I don't know how to display it as 149. I can only show it as
1
4
9
Sure, I might try adding it to an array then for looping the results... something tells me that this is the slow solution, and that there is a faster one. Here's my code.
function squareDigits(num) {
//Convert input to string
num = num + "";
var newnum;
var len = num.length;
//Split into digits, and square that result baby
for (i = 0; i < len; i++) {
var digit = num.substr(i, 1);
newnum = Math.pow(digit, 2);
console.log(newnum);
}
}
squareDigits(123);
Create empty array outside of the loop
Add squares of the each digit in the array
Join the array after loop finishes
function squareDigits(num) {
num = '' + num;
var len = num.length;
var squares = []; // Define empty array
//Split into digits, and square that result baby
for (i = 0; i < len; i++) {
var digit = num.substr(i, 1);
squares.push(Math.pow(digit, 2)); // Push the square of the digit at the end of array
}
return squares.join(''); // Join the array elements with empty string as glue
}
var squares = squareDigits(123);
console.log(squares);
document.write(squares);
By string concatenation
Declare a empty string before the for loop
Concatenate the square of the digit to the string by first casting the number to string
function squareDigits(num) {
//Convert input to string
num = num + "";
var newnum = ''; // Decalare variable with Empty string
var len = num.length;
//Split into digits, and square that result baby
for (i = 0; i < len; i++) {
var digit = num.substr(i, 1);
newnum += '' + Math.pow(digit, 2); // Cast the square to string and then concatenate to the string
}
return newnum; // Return the string
}
var squares = squareDigits(123);
document.write(squares);
Try utilizing String.prototype.split() , Array.prototype.map() , Array.prototype.join()
function squareDigits(num) {
return String(num).split("")
.map(function(n) {
return Math.pow(n, 2);
}).join("");
}
console.log(squareDigits(123));
What about this?
function squareDigits(num) {
//Convert input to string
num = num + "";
var newnum;
var len = num.length;
var digits = '';
//Split into digits, and square that result baby
for (i = 0; i < len; i++) {
var digit = num.substr(i, 1);
newnum = Math.pow(digit, 2);
digits += '' + newnum
}
console.log(digits);
}
try process.stdout.write, as in
process.stdout.write(newnum);

Validation for numeric data Javascript

I'm writing a program in Javascript that separates even and odd numbers, puts them into an array, adds the sum of numbers, and finds the average.
I'm having an issue not allowing zeros not to count. Because its adding to the array, and when the user types in 6+6, sum is 12, average is calculating to 4 because of the extra 0 in the array.
Is there anyway to not allow the zeros to count? Here is what I have so far..
var evenarray = [];
var oddarray = [];
var avgEven = 0;
var avgOdd = 0;
var isValid;
function numberFunction(){
do
{
var numbers = prompt("Please enter numbers. Enter empty string to exit.");
if(numbers % 2 == 0)
{
evenarray.push(numbers);
var sumEven = 0;
for (var i=0; i < evenarray.length; i++)
{
sumEven = sumEven + Number(evenarray[i]);
}
var avgEven = sumEven/evenarray.length;
//alert("even");
}
if(numbers % 2 !== 0)
{
oddarray.push(numbers);
var sumOdd = 0;
for (var i=0; i < oddarray.length; i++)
{
sumOdd = sumOdd + Number(oddarray[i]);
}
var avgOdd = sumOdd/oddarray.length;
//alert("odd");
}
//if(isNaN(numbers)){
//alert("Only numeric data only");
//}
}
while(numbers !== "");
Just do nothing when the number is actually 0:
if (numbers == 0)
{
}
else if(numbers % 2 == 0)
{
evenarray.push(numbers);
var sumEven = 0;
for (var i=0; i < evenarray.length; i++)
{
sumEven = sumEven + Number(evenarray[i]);
}
var avgEven = sumEven/evenarray.length;
}
else // only odds remain
{
oddarray.push(numbers);
var sumOdd = 0;
for (var i=0; i < oddarray.length; i++)
{
sumOdd = sumOdd + Number(oddarray[i]);
}
var avgOdd = sumOdd/oddarray.length;
}
You can do :
if(numbers % 2 == 0 && numbers !=0) ...
if(numbers % 2 != 0 && numbers !=0) ...
so that you don't do anything when numbers == 0;
It's a little strange to call your variable numbers instead of number.
your function should be,
function numberFunction(){
do
{
var numbers = prompt("Please enter numbers. Enter empty string to exit.");
if(numbers !=0 && !isNaN(numbers))
(numbers %2 == 0)? (evenarray.push(parseInt(numbers))) : (oddarray.push(parseInt(numbers)));
}while(numbers !== "");
for(var i = 0; i < evenarray.length; i++)
sumEven += evenarray[i];
for(var i = 0; i < oddarray.length; i++)
sumOdd += oddarray[i];
avgEven = sumEven / evenarray.length;
avgOdd = sumOdd / oddarray.length;
document.getElementById("even").innerHTML = evenarray.toString();
document.getElementById("sumEvenTotal").innerHTML = sumEven.toString(); //displays sum of even numbers.
document.getElementById("averageOdd").innerHTML = avgOdd; //displays average of odd numbers.
document.getElementById("averageEven").innerHTML = avgEven; //diplays average of even numbers.
document.getElementById("odd").innerHTML = oddarray.toString(); //displays all odd numbers that were entered.
document.getElementById("sumOddTotal").innerHTML = sumOdd.toString();
}
As you already have other answers with solutions to your particular issue, I would suggest a different approach. Think of the data you're manipulating: an array. Try to solve the issue only with data, no user input, no DOM manipulation; just data. This helps to separate concerns, and make your code easier to understand.
Since we're working with arrays, we can make use of some of the built-in JavaScript methods that are present in modern browsers, such as filter and reduce. These methods are in a way, alternatives to for loops, with some pre-defined behavior, and a callback function.
Now, let's think of the steps involved in solving your problem.
Get numbers from the user. We can represent this data as an array, as you were already doing.
We want all odd numbers, their sum and average.
We want all even numbers, their sum and average.
We display the data to the user.
In this solution I'm assuming you already have an array with the data, and will be focusing on points 2 and 3. Remember, think of data, user interaction shouldn't be mixed with your data logic. Instead of asking the user for a number on each loop, you could ask the user for a list of numbers directly; you avoid multiple prompts this way, and it lets you separate data and interaction nicely. Ideally you'd validate all user input to match your requirements.
// Helpers to work with numbers
var odd = function(x) {
return x % 2 === 0;
};
var even = function(x) {
return x % 2 !== 0;
};
var add = function(x, y) {
return x + y;
};
function solve(ns) {
// Solve the problem
// with odd or even numbers
var result = function(fn) {
var xs = ns.filter(fn); // odd or even
var sum = xs.reduce(add);
return {
numbers: xs,
sum: sum,
average: sum / xs.length
};
};
// Return an object
// with odd and even results
return {
odd: result(odd),
even: result(even)
};
}
var numbers = [1,2,3,4]; // from user input
var result = solve(numbers);
console.log(result.odd);
//^ {numbers: [2,4], sum: 6, average: 3}
console.log(result.even);
//^ {numbers: [1,2], sum: 4, average: 2}

Testing for a common word between 2 strings in javascript

I have to match 2 strings where at least one word is same, I need to give a success msg.
var str1 = "Hello World";
var str2 = "world is beautiful";
I need to match/compare these 2 strings, in both strings world is matching, So i need to print a success message. How do I go about it.
The following code will output all the matching words in the both strings:
var words1 = str1.split(/\s+/g),
words2 = str2.split(/\s+/g),
i,
j;
for (i = 0; i < words1.length; i++) {
for (j = 0; j < words2.length; j++) {
if (words1[i].toLowerCase() == words2[j].toLowerCase()) {
console.log('word '+words1[i]+' was found in both strings');
}
}
}
You can avoid comparing all the words in one list with all the words in the other by sorting each and eliminating duplicates. Adapting bjornd's answer:
var words1 = str1.split(/\s+/g),
words2 = str2.split(/\s+/g);
var allwords = {};
// set 1 for all words in words1
for(var wordid=0; wordid < words1.length; ++wordid) {
var low = words1[wordid].toLowerCase();
allwords[low] = 1;
}
// add 2 for all words in words2
for(var wordid=0; wordid < words2.length; ++wordid) {
var current = 0;
var low = words2[wordid].toLowerCase();
if(allwords.hasOwnProperty(low)) {
if(allwords[low] > 1) {
continue;
}
}
current += 2;
allwords[low] = current;
}
// now those seen in both lists have value 3, the rest either 1 or 2.
// this is effectively a bitmask where the unit bit indicates words1 membership
// and the 2 bit indicates words2 membership
var both = [];
for(var prop in allwords) {
if(allwords.hasOwnProperty(prop) && (allwords[prop] == 3)) {
both.push(prop);
}
}
This version should be reasonably efficient, because we are using a dictionary/hash structure to store information about each set of words. The whole thing is O(n) in javascript expressions, but inevitably dictionary insertion is not, so expect something like O(n log n) in practise. If you only care that a single word matches, you can quit early in the second for loop; the code as-is will find all matches.
This is broadly equivalent to sorting both lists, reducing each to unique words, and then looking for pairs in both lists. In C++ etc you would do it via two sets, as you could do it without using a dictionary and the comparison would be O(n) after the sorts. In Python because it's easy to read:
words1 = set(item.lower() for item in str1.split())
words2 = set(item.lower() for item in str2.split())
common = words1 & words2
The sort here (as with any set) happens on insertion into the set O(n log n) on word count n, and the intersection (&) is then efficent O(m) on the set length m.
I just tried this on WriteCodeOnline and it works there:
var s1 = "hello world, this is me";
var s2 = "I am tired of this world and I want to get off";
var s1s2 = s1 + ";" + s2;
var captures = /\b(\w+)\b.*;.*\b\1\b/i.exec(s1s2);
if (captures[1])
{
document.write(captures[1] + " occurs in both strings");
}
else
{
document.write("no match in both strings");
}
Just adapting #Phil H's code with a real bitmask:
var strings = ["Hello World", "world is beautiful"]; // up to 32 word lists
var occurrences = {},
result = [];
for (var i=0; i<strings.length; i++) {
var words = strings[i].toLowerCase().split(/\s+/),
bit = 1<<i;
for (var j=0, l=words.length; j<l; j++) {
var word = words[j];
if (word in occurrences)
occurrences[word] |= bit;
else
occurrences[word] = bit;
}
}
// now lets do a match for all words which are both in strings[0] and strings[1]
var filter = 3; // 1<<0 | 1<<1
for (var word in occurrences)
if ((occurrences[word] & filter) === filter)
result.push(word);
OK, the simple way:
function isMatching(a, b)
{
return new RegExp("\\b(" + a.match(/\w+/g).join('|') + ")\\b", "gi").test(b);
}
isMatching("in", "pin"); // false
isMatching("Everything is beautiful, in its own way", "Every little thing she does is magic"); // true
isMatching("Hello World", "world is beautiful"); // true
...understand?
I basically converted "Hello, World!" to the regular expression /\b(Hello|World)\b/gi
Something like this would also do:
isMatching = function(str1, str2) {
str2 = str2.toLowerCase();
for (var i = 0, words = str1.toLowerCase().match(/\w+/g); i < words.length; i++) {
if (str2.search(words[i]) > -1) return true;
}
return false;
};
var str1 = "Hello World";
var str2 = "world is beautiful";
isMatching(str1, str2); // returns true
isMatching(str1, 'lorem ipsum'); // returns false

Sorting function?

I need to organize an array of strings of random length into the least number of new strings with a max size. Is there a function or something in javascript, or something that can be translated to javascript, that will do this?
For example, the new strings might have max lengths of 1000 characters. The array might have strings of lengths 100, 48, 29, etc. I would want to combine those strings into as few new strings as possible.
edit: Sorry if this doesn't make sense, I tried my best.
No standard method in Javascript, but plenty of theoretical work has been done on this (i.e. the bin packing problem).
http://en.wikipedia.org/wiki/Bin_packing_problem
Some sample pseudo code in the link - should be trivial to translate to javascript.
The algorithm shown isn't going to be optimal in every case. To find the optimal solution to your example you'll just need to iterate over every possibility which might not be that bad depending on how many strings you have.
For my own entertainment, I wrote a simple bin packing algorithm. I picked a simple algorithm which is to sort the input strings by length. Create a new bin. Put the first (longest remaining) string into the bin and then keep filling it up with the longest strings that will fit until no more strings will fit. Create a new bin, repeat. To test it, I allocate an array of strings of random lengths and use that as input. You can see the output visually here: http://jsfiddle.net/jfriend00/FqPKe/.
Running it a bunch of times, it gets a fill percentage of between 91-98%, usually around 96%. Obviously the fill percentage is higher if there are more short strings to fill with.
Here's the code:
function generateRandomLengthStringArrays(num, maxLen) {
var sourceChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY1234567890";
var sourceIndex = 0;
var result = [];
var len, temp, fill;
function getNextSourceChar() {
var ch = sourceChars.charAt(sourceIndex++);
if (sourceIndex >= sourceChars.length) {
sourceIndex = 0;
}
return(ch);
}
for (var i = 0; i < num; i++) {
len = Math.floor(Math.random() * maxLen);
temp = new String();
fill = getNextSourceChar();
// create string
for (var j = 0; j < len; j++) {
temp += fill;
}
result.push(temp);
}
return(result);
}
function packIntoFewestBins(input, maxLen) {
// we assume that none of the strings in input are longer than maxLen (they wouldn't fit in any bin)
var result = [];
// algorithm here is to put the longest string into a bin and
// then find the next longest one that will fit into that bin with it
// repeat until nothing more fits in the bin, put next longest into a new bin
// rinse, lather, repeat
var bin, i, tryAgain, binLen;
// sort the input strings by length (longest first)
input.sort(function(a, b) {return(b.length - a.length)});
while (input.length > 0) {
bin = new String(); // create new bin
bin += input.shift(); // put first one in (longest we have left) and remove it
tryAgain = true;
while (bin.length < maxLen && tryAgain) {
tryAgain = false; // if we don't find any more that fit, we'll stop after this iteration
binLen = bin.length; // save locally for speed/convenience
// find longest string left that will fit in the bin
for (i = 0; i < input.length; i++) {
if (input[i].length + binLen <= maxLen) {
bin += input[i];
input.splice(i, 1); // remove this item from the array
tryAgain = true; // try one more time
break; // break out of for loop
}
}
}
result.push(bin);
}
return(result);
}
var binLength = 60;
var numStrings = 100;
var list = generateRandomLengthStringArrays(numStrings, binLength);
var result = packIntoFewestBins(list, binLength);
var capacity = result.length * binLength;
var fillage = 0;
for (var i = 0; i < result.length; i++) {
fillage += result[i].length;
$("#result").append(result[i] + "<br>")
}
$("#summary").html(
"Fill percentage: " + ((fillage/capacity) * 100).toFixed(1) + "%<br>" +
"Number of Input Strings: " + numStrings + "<br>" +
"Number of Output Bins: " + result.length + "<br>" +
"Bin Legnth: " + binLength + "<br>"
);

Categories

Resources