How to Align Text in Browser Console Properly? - javascript

I have a task to take values from a prompt and put them like in the picture, but I don’t really understand how to make everything on the same level, for example, so that the '|' was always under the plus, not paying attention to the length of the word.
My result:
var arr = []
for (var i = 0; i >= 0; i++) {
var input = prompt('Enter any value (enter end to complete the operation) ');
if (input === 'end') break;
arr[i] = input;
}
console.log(arr)
for (var i = 0; i < arr.length; i++) {
console.log(`+-----------------+---------------------+ \n| ${arr[i]} |`)
}

You can do something like this, but fonts have variable widths so I don't expect this to work 100%.
var maxLength = 21;
var arr = []
for (var i = 0; i >= 0; i++) {
var input = prompt('Enter any value (enter end to complete the operation) ');
if (input === 'end') break;
arr[i] = input;
}
console.log(arr)
for (var i = 0; i < arr.length; i++) {
console.log(`+${'-'.repeat(maxLength-1)}+${'-'.repeat(maxLength-1)}+ \n|${' '.repeat((maxLength-arr[i].length)/2)}${arr[i]}${' '.repeat((maxLength-arr[i].length)/2)}|`)
}
For example number 2 is wider than 1 so this happens:

An alternative that lets you adjust your spacing and width of your 'columns'. Choose a font that has equal width for all characters for this to work.
const arr = ['ab', 'abc', 'abcdef', 'a']
// Figure out the max length of your string array
let max = 0
arr.forEach(s => {
if (max < s.length) max = s.length
})
// Set your column with -
const spacing = 3
const dashes = '-'.repeat(max + spacing * 2);
const firstLine = `+${dashes}+`
console.log(firstLine)
for (let i = 0; i < arr.length; i++) {
const padLeft = Math.floor((max - arr[i].length) / 2)
const padRight = max - arr[i].length - padLeft
console.log('|' + ' '.repeat(spacing + padLeft) + arr[i] + ' '.repeat(spacing + padRight) + '|')
}
console.log(firstLine)

The following solution will add 5 or more spaces to each side of each string and add an extra space to even length strings in order to insure evenly spaced vertical borders. As long as the font is a monospace typeface (which is the console default) the content will be displayed perfectly aligned.
Note, in the second image in the OP (Original Post) each string is in it's own "cell" within it's own "row", whilst the first image in the OP shows 2 strings within it's own "cell" on each "row". My answer coincides with the former since the code in OP does as well.
Determine total number of characters of the longest string in array and divide it by 2.
// Define >max< outside of loop
let max = 0;
// Compare and redefine >max< within loop
if (max < (input.length / 2)) max = input.length / 2
Define border outside of loop which should accommodate the longest string in the array plus 5 spaces on both of it's sides.
const border = `+${"-".repeat(max + 5)}+${"-".repeat(max + 5)}+ \n`;
Define space within loop so the value changes according to current string to be displayed.
let space = (max - (arr[i].length / 2)) + 5;
Define offset for even length strings
/* If the remainder of the string length divided by 2 is 0, then >offset< is 1
else it's 0 */
let offset = arr[i].length % 2 === 0 ? 1 : 0;
Finally, interpolate each string within the loop.
`${border}|${" ".repeat(space)}${arr[i]}${" ".repeat(space + offset)}|`
Example
let arr = [];
let max = 0;
for (let i = 0; i >= 0; i++) {
let input = prompt('Enter any value (enter "end" to complete the operation) ');
if (input === 'end') break;
arr[i] = input;
if (max < input.length / 2) max = input.length / 2;
}
console.log(arr)
const border = `+${"-".repeat(max + 5)}+${"-".repeat(max + 5)}+ \n`;
for (let i = 0; i < arr.length; i++) {
let space = (max - (arr[i].length / 2)) + 5;
let offset = arr[i].length % 2 === 0 ? 1 : 0;
console.log(`${border}|${" ".repeat(space)}${arr[i]}${" ".repeat(space + offset)}|`);
}
console.log(border);

Related

How can I know if the characters of a string repeat themselves the same amount of times when they have a wildcard built-in?

examples:
testing("xyzy**") should be true.
testing("xyzy*") should be false.
Reasoning:
In the first case, it is true because one * can behave as a x and the other a z, so all characteres would of the same amount of y.
In the second case there wouldn't be the same amount of characters repeating itself, cause there is only one *, so it is false.
Here is what I have up until now:
const testing = string => {
var array = []; //array with each character without repeating
var array_R = []; //array with the value the value that each character repeats itself
var array_C = 0; //counter for the size of "array"
//getting the character without repeating
for (var i = 0; i < string.length; i++) {
if (!array.includes(string.charAt(i))) {
array[array_C] = string.charAt(i);
array_R[array_C] = 0;
array_C++;
}
}
//how many each character repeats itself
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < string.length; j++) {
if(array[i] == string.charAt(j)){
array_R[i] = array_R[i] + 1;
}
}
}
}
I really don't know how I can proceed from here.
First count up the number of occurrences of each non-* character into an object or Map. Find the maximum value in that collection, then find the sum of all differences between the maximum value and each value. If the number of asterisks is the same as the sum of differences, the repeat conditions are fulfilled.
You'll also have to consider the case where there are more asterisks left over after all holes are filled in to make the values equal - figure out how many are left over, and see if that evenly divides the number of separate characters.
const testing = (str) => {
const grouped = {};
for (const char of str) {
if (char !== '*') grouped[char] = (grouped[char] || 0) + 1;
}
const values = Object.values(grouped);
const numOfSeparateChars = values.length;
const max = Math.max(...values);
const sum = values.reduce((a, b) => a + b, 0);
const sumOfDifferencesFromMax = max * numOfSeparateChars - sum;
const numberAsterisks = (str.match(/\*/g) || []).length;
const remainingAsterisks = sumOfDifferencesFromMax - numberAsterisks;
// Now all characters have been filled in to make the values even
// eg: 'abcc**' -> 'abccab'
// But there may be more asterisks
// eg: 'abcc*****' -> 'abccaabbc'
return remainingAsterisks % numOfSeparateChars === 0;
};
console.log(testing("xyzy**"));
console.log(testing("xyzy*"));

Split a range of number to a specific number of intervals

I have an interval [0; max] and I want to split it into a specific number of sub-intervals. For this, i wrote a function called getIntervalls(max, nbIntervals) where max is the max element in my first interval and nbIntervals is the number of expected sub-intervals.
For example:
getIntervalls(3, 2) should return [[0,1], [2,3]],
getIntervalls(6, 2) should return [[0,3], [4,6]],
getIntervalls(8, 3) should return [[0,2], [3,5], [6,8]],
getIntervalls(9, 3) should return [[0,3], [4,7], [8,9]],
Here is my function:
function getIntervalls(max, nbIntervalls) {
var size = Math.ceil(max / nbIntervalls);
var result = [];
if (size > 1) {
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size: max;
result .push([inf, sup]);
}
} else {
result.push([0, max]);
}
return result;
}
console.log(JSON.stringify(getIntervalls(7, 2)));
It work properly, and shows this output:
[[0,4],[5,7]]
When I change the parameters to 7 and 3, it shows:
[[0,3],[4,7],[8,7]]
instead of
[[0,2],[3,5],[6,7]]
Would anyone can help me? Thank you in advance. An ES6 syntax will be appreciated! :)
You need to use Math.round() for take the nearest integer of the decimal number of the size of interval. Also, you need to descrease a one the max for size calculation to take account of the effective number of interval.
Here the modification of your code :
function getIntervalls(max, nbIntervalls) {
var size = Math.round((max-1) / nbIntervalls);
var result = [];
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size: max;
result.push([inf, sup]);
if(inf >= max || sup >= max)break;
}
return result;
}
Note that it respect the wanted number of interval, so some case of couple of number can result
[..., [n-2,n-1], [n,n]].
Hope this helps!
You could check if i is zero for first element and if next increment is larger then max for second element. Also you can check if first element is smaller then max.
function getIntervalls(max, nInt) {
const c = Math.floor(max / nInt);
const r = [];
for (var i = 0; i <= max; i += c) {
const a = i == 0 ? i : i += 1;
const b = i + c > max ? max : i + c;
if (a < max) r.push([a, b])
}
return r;
}
console.log(JSON.stringify(getIntervalls(3, 2)));
console.log(JSON.stringify(getIntervalls(6, 2)));
console.log(JSON.stringify(getIntervalls(8, 3)));
console.log(JSON.stringify(getIntervalls(9, 3)));
console.log(JSON.stringify(getIntervalls(7, 2)));
console.log(JSON.stringify(getIntervalls(7, 3)));
You need to change the size calculation from Math.ceil() to Math.floor(), because of ceil it takes size +1 than what you need.
I have made modification to your code, here it will work.
function getIntervalls(max, nbIntervalls) {
var size = Math.floor(max / nbIntervalls);
var result = [];
if (size > 0) {
for (let i = 0; i < nbIntervalls; i++) {
var inf = i + i * size;
var sup = inf + size < max ? inf + size : max;
result .push([inf, sup]);
if (sup >= max) {
break;
}
}
} else {
result.push([0, max]);
}
return result;
}
console.log(JSON.stringify(getIntervalls(10, 5)));
Hope this helps!
For me, this is the perfect function for that.
It allows you to get the intervals between two numbers, and the last interval always goes to the max.
function getIntervals(min, max, nbIntervals) {
let size = Math.floor((max - min) / nbIntervals);
let result = [];
if (size <= 0) return [min, max];
for (let i = 0; i < nbIntervals; i++) {
let inf = min + (i * size);
let sup = ((inf + size) < max) ? inf + size : max;
if (i === (nbIntervals - 1)) {
if (sup < max) sup = max;
}
result.push([inf, sup]);
if (sup >= max) break;
}
return result;
}

Creating a large letter X

I am trying to create a script that allows the user to enter a certain amount of rows which will then print a large letter X, so far I am able to print it as a v shape but am struggling to get the rest of the x together.
rows = 0;
space = " ";
var user_input = parseFloat(prompt("Enter how many rows:", 0));
while (rows < user_input) {
space_counter = 0;
while (space_counter < rows) { //process1
document.write(space);
space_counter++;
}
document.write("x"); //process2
rows++;
midspace_counter = 0;
while (midspace_counter < user_input - rows) { //process3
document.write(space + space);
midspace_counter++;
}
document.write("x<br>"); //process4
rows++;
}
How i would do that:
let result = "";
const maxRow = +prompt("how many rows?");
// Knowing the half size of our x might be useful
const half = (maxRow - 1) / 2;
for(let row = 0; row < maxRow; row++){
// For e.g. maxRow = 7 this will be 3 2 1 0 1 2 3
const midspace = Math.abs(half - row);
const pad = maxRow - midspace - 1;// 1 = "x"
// \n means newline
result += " ".repeat(pad) + "x" + " ".repeat(midspace * 2) + "x\n";
}
Then you just need to append that to the document.

Find all permutations of smaller string s in string b (JavaScript)

I've been trying to find a O(n) solution to the following problem: Find the number of anagrams (permutations) of string s in string b, where s.length will always be smaller than b.length
I read that the optimal solution involves keeping track of the frequencies of the characters in the smaller string and doing the same for the sliding window as it moves across the larger string, but I'm not sure how that implementation actually works. Right now my solution doesn't work (see comments) but even if it did, it would take O(s + sn) time.
EDIT: Sample input: ('aba', 'abaab'). Output: 3, because 'aba' exists in b starting at index 0, and 'baa' at 1, and 'aab' at 2.
function anagramsInStr(s,b) {
//O(s)
let freq = s.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
let i = 0, j = s.length;
// O(n)
for (let char in b.split("")) {
// O(s)
if (b.length - char + 1 > s.length) {
let window = b.slice(i,j);
let windowFreq = window.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
// Somewhere about here compare the frequencies of chars found in the window to the frequencies hash defined in the outer scope.
i++;
j++;
}
}
}
Read through the comments and let me know if you have any questions:
function countAnagramOccurrences(s, b) {
var matchCount = 0;
var sCounts = {}; // counts for the letters in s
var bCounts = {}; // counts for the letters in b
// construct sCounts
for (var i = 0; i < s.length; i++) {
sCounts[s[i]] = (sCounts[s[i]] || 0) + 1;
}
// all letters that occur in sCounts
var letters = Object.keys(sCounts);
// for each letter in b
for (var i = 0; i < b.length; i++) {
// maintain a sliding window
// if we already have s.length items in the counts, remove the oldest one
if (i >= s.length) {
bCounts[b[i-s.length]] -= 1;
}
// increment the count for the letter we're currently looking at
bCounts[b[i]] = (bCounts[b[i]] || 0) + 1;
// test for a match (b counts == s counts)
var match = true;
for (var j = 0; j < letters.length; j++) {
if (sCounts[letters[j]] !== bCounts[letters[j]]) {
match = false;
break;
}
}
if (match) {
matchCount += 1;
}
}
return matchCount;
}
console.log(countAnagramOccurrences('aba', 'abaab')); // 3
EDIT
A note about the runtime: this is sort of O(nk + m), where n is the length of s, m is the length of b, and k is the number of unique characters in b. Since m is always less than n, we can reduce to O(nk), and since k is bounded by a fixed constant (the size of the alphabet), we can further reduce to O(n).

Function to count how many numbers are there with the digits and division value specified

I started making a function that will be able do the following: Count how many 6 digit numbers you can make with the digits 0,1,2,3,4 and 5, that can be divided by 6?
How I currently try to start, is I make an array of all the possible numbers, then take out every number that has any of the numbers' arrays elements in it, then remove the ones that are not dividable with 6.
I got stuck at the second part. I tried making 2 loops to loop in the array of numbers, then inside that loop, create an other one for the length of the allnumbers array to remove all matches.
Then I would use the % operator the same way to get every element out that doesn't return 0.
The code needs to be flexible. If the user asks for eg. digit 6 too, then the code should still work. Any way I could finish this?
My Code is:
var allnumbers = [],j;
var biggestnumber = "999999999999999999999999999999999999999999999999999999999999";
function howmanynumbers(digits,numbers,divideWith){
if (digits && numbers && divideWith){
for (var i = 0; i < 1+Number(biggestnumber.substring(0,digits)); i++ ){
allnumbers.push(i);
}
for (j = 0; j < numbers.length; j++ ){
var matchit = new RegExp(numbers[j]);
}
//not expected to work, I just had this in for reference
if ( String(allnumbers[i]).match(matchit) != [""]){
j = 0;
allnumbers.splice(i,1);
var matchit = new RegExp(numbers[j])
}
}
else {
return false;
}
}
This is my take on the entire solution:
var i;
var allowedDigitsPattern = /^[0-5]+$/i;
var numbers = [];
for (i = 100000; i < 555555; i++) {
if (allowedDigitsPattern.test(i.toString())
&& i % 6 === 0) {
numbers.push(i);
}
}
And you can look at your results like this:
document.write('There are ' + numbers.length + ' numbers<br>');
// write out the first ten!
for (i = 0; i < 10; i++) {
document.write(numbers[i] + '<br>');
}
Update based on comments...
The configurable version of this would be:
var i;
var lowestDigit = 0;
var highestDigit = 5;
var numberOfDigits = 6;
var allowedDigitsPattern = new RegExp('^[' + lowestDigit + '-' + highestDigit + ']+$', 'gi');
var smallestNumber = '1';
for (i = 1; i < numberOfDigits; i++) {
smallestNumber += '0';
}
var biggestNumber = '';
for (i = 0; i < numberOfDigits; i++) {
biggestNumber += highestDigit.toString();
}
var numbers = [];
for (i = smallestNumber; i < biggestNumber; i++) {
if (allowedDigitsPattern.test(i.toString())
&& i % 6 === 0) {
numbers.push(i);
}
}
document.write('There are ' + numbers.length + ' numbers<br>');
You need to change the smallest and largest numbers based on the configuration. I have made both the allowable digits and the length of the number configurable.

Categories