How do I solve this specific algorithm in JavaScript? - javascript

Given this array: arr = [ '00011100', '00000001', '00101101', '11111111' ];
If the element is on even position in the array, I have to remove all the chars with even index from this element and vice versa. Example:
The first element is on even position:
arr[0] = '00011100'
The second element is on odd position:
arr[1] = '00000001';
I have to remove those characters and return them as concatenated string.
Output of the whole array // 0110 0000 0011 1111
Please, help me solve this task :) Thank you in advance!
let enigma = "";
for(let i = 0; i < arr.length; i++){
let index = arr[i];
let evenStr = "";
let oddStr = "";
if(index % 2 === 0) {
for(let j = 1; j < index.length; j+=2) {
evenStr += index[j];
} enigma += evenStr;
} else if(index % 2 !== 0) {
for(let x = 1; x < index.length; x+=2) {
oddStr += index[x];
} enigma += oddStr;
}
}
console.log(enigma) //0110000100111111;
This is my code so far but the output I recieve is slightly different :/

Here is a potential solution to your problem.
Using reduce()
const removeOddIndex = ( str ) => {
return str.split("").filter( ( element, index ) => index % 2).join("");
}
const removeEvenIndex = ( str ) => {
return str.split("").filter( ( element, index ) => !( index % 2 )).join("");
}
const array = [ '00011100', '00000001', '00101101', '11111111' ];
const result = array.reduce( ( acc, cur, index ) => {
if( index % 2 ) {
acc[index] = removeEvenIndex( cur );
} else {
acc[index] = removeOddIndex( cur );
}
return acc;
}, array).join("")
console.log(result)
Using map()
const removeOddIndex = ( str ) => {
return str.split("").filter( ( element, index ) => index % 2).join("");
}
const removeEvenIndex = ( str ) => {
return str.split("").filter( ( element, index ) => !( index % 2 )).join("");
}
const array = [ '00011100', '00000001', '00101101', '11111111' ];
const result = array.map( ( element, index ) => {
return index % 2 ? removeEvenIndex( element ) : removeOddIndex( element )
} ).join("");
console.log(result)

You can easily achieve this using map, split and join
const arr = ["00011100", "00000001", "00101101", "11111111"];
const getEven = (value) =>
value
.split("")
.filter((el, i) => i % 2 === 0)
.join("");
const getOdd = (value) =>
value
.split("")
.filter((el, i) => i % 2 === 1)
.join("");
const result = arr
.map((val, index) => {
if (index % 2 === 0) return getOdd(val);
else return getEven(val);
})
.join("");
console.log( result );

You could filter by taking the remainder of the item of the outer element and the elment's values.
const
array = ['00011100', '00000001', '00101101', '11111111'],
result = array.map(([...a], i) => a.filter((v, j) => i % 2 !== j % 2).join(''));
console.log(result);

Related

sample array n^2 times without the same number occurring twice in a row and not repeating every n

I'm trying to write a function that has the arguments of the array to sample arr and the number of samples, size (which is sqaured) and randomly samples from the original array:
arr = [1,2,3,4]
single_number = (x) => {
return x[Math.floor(Math.random()*x.length)];
}
randomize = (arr, size) => {
return Array(size*size).fill().map(x => single_number(arr))
}
randomize(arr, 5)
I want to add the additional requirements to my randomize function:
no number shows up twice in a row
make sure every sizeth item is not the same as the one before it
For example
randomize([1,2,3,4], 2)
[2,4,3,2,4,1,1,2,2,1,4,1,1,1,3,1,1,4,4,1,3,3,2,2,3]
CASE (1)
[
2,4,3,2,4,
2,1,
2,2, // illegal!
1,4,
1,1,1, // illegal!
3,
1,1, // illegal!
4,4, // illegal!
1,
3,3, // illegal!
2,2, // illegal!
3
]
CASE (2)
[
2,4,3,2,4, [0] === 2
2,1,2,2,1, [5] === 2 // illegal!
4,1,1,1,3,
1,1,4,4,1,
3,3,2,2,3
]
I'm trying to use functional programming and avoid a for loop if possible since I think I can do this with a nested for loop?
Well, this isn't as pretty as one would hope, but I think it accomplishes the objective: Iterate size^2 times and choose random elements from the input, taking care to exclude the last value and last nth value chosen...
const randomize = (array, size) => {
const rand = () => Math.floor(Math.random() * array.length);
const randExcept = exclude => {
let v = array[rand()];
while (exclude.includes(v)) v = array[rand()];
return v;
}
const indexes = Array.from(Array(size*size).keys());
let lastV = null, nthV = null;
return indexes.map(i => {
let exclude = nthV!==null && i%size===1 ? [lastV, nthV] : [lastV];
let v = randExcept(exclude);
lastV = v;
if (i%size===1) nthV = v;
return v;
})
}
console.log( JSON.stringify(randomize([1,2,3,4], 2)) )
This defines nth values by the count into the array, so for size===2, the constraint is that every second element (indexes 1,3,5...) can't be equal to the prior second element.
I'd probably do something like this:
const values = [1,2,3,4]
function randomize(values, size) {
let prev;
let prevNth;
return Array(size*size).fill().map( randomNumber );
function randomNumber(_,i) {
let value, ok;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
ok = value != prev;
if ( i % size === 0) {
ok = ok && value != prevNth;
prevNth = value;
}
prev = value;
} while (!ok);
return value;
}
}
arr = randomize(values, 5)
console.log(JSON.stringify(arr));
Or this, using a generator to generate the appropriately sized stream of randomness:
const values = [1,2,3,4];
const arr1 = Array.from( randomValues(5,values) );
console.log(JSON.stringify(arr1));
function *randomValues(n, values) {
const limit = n*n;
let prev, prevNth;
for ( let i = 0 ; i < limit ; ++i ) {
const isNthValue = i % n === 0;
const value = randomValue( values, prev, isNthValue ? prevNth : undefined );
yield value;
prev = value;
prevNth = isNthValue ? value : prevNth;
}
}
function randomValue(values, test1, test2 ) {
let value;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
} while (value === test1 || value === test2 );
return value;
}

Inconsistency, when returning index of duplicate values

I'm trying to create an algorithm to find duplicate values in a list and return their respective indexes, but the script only returns the correct value, when I have 2 equal elements:
array = [1,2,0,5,0]
result -> (2) [2,4]
Like the example below:
array = [0,0,2,7,0];
result -> (6) [0, 1, 0, 1, 0, 4]
The expected result would be [0,1,4]
Current code:
const numbers = [1,2,0,5,0];
const checkATie = avgList => {
let averages, tie, n_loop, currentAverage;
averages = [... avgList];
tie = [];
n_loop = 0;
for(let n = 0; n <= averages.length; n++) {
currentAverage = parseInt(averages.shift());
n_loop++
for(let avg of averages) {
if(avg === currentAverage) {
tie.push(numbers.indexOf(avg),numbers.indexOf(avg,n_loop))
};
};
};
return tie;
}
console.log(checkATie(numbers));
if possible I would like to know some way to make this code more concise and simple
Use a Set
return [...new Set(tie)]
const numbers1 = [1,2,0,5,0];
const numbers2 = [0,0,2,7,0];
const checkATie = avgList => {
let averages, tie, n_loop, currentAverage;
averages = [... avgList];
tie = [];
n_loop = 0;
for(let n = 0; n <= averages.length; n++) {
currentAverage = parseInt(averages.shift());
n_loop++
for(let avg of averages) {
if(avg === currentAverage) {
tie.push(avgList.indexOf(avg),avgList.indexOf(avg,n_loop))
};
};
};
return [...new Set(tie)]
}
console.log(checkATie(numbers1));
console.log(checkATie(numbers2));
I hope this help you.you can use foreach function to check each item of array
var array = [0,0,2,7,0];
var result = [] ;
array.forEach((item , index)=>{
if(array.findIndex((el , i )=> item === el && index !== i ) > -1 ){
result.push(index)
}
})
console.log(result);
//duplicate entries as an object
checkDuplicateEntries = (array) => {
const duplicates = {};
for (let i = 0; i < array.length; i++) {
if (duplicates.hasOwnProperty(array[i])) {
duplicates[array[i]].push(i);
} else if (array.lastIndexOf(array[i]) !== i) {
duplicates[array[i]] = [i];
}
}
console.log(duplicates);
}
checkDuplicateEntries([1,2,0,5,0]);
// hope this will help
Create a lookup object with value and their indexes and then filter all the values which occurred more than once and then merge all indexes and generate a new array.
const array = [1, 2, 0, 5, 0, 1, 0, 2],
result = Object.values(array.reduce((r, v, i) => {
r[v] = r[v] || [];
r[v].push(i);
return r;
}, {}))
.filter((indexes) => indexes.length > 1)
.flatMap(x => x);
console.log(result);

Removing consecutive duplicate characters

I am trying to remove consecutive duplicate characters from the string. So the input of aabbcde should output as cde.
I wrote the following code, but I am getting the incorrect output. I could not understand why.
var a = "aabbccddeef"
var ncopy = a;
let leftPointer = 0;
let rightPointer = 1;
let posList = [];
while (true) {
if (a[leftPointer] == a[rightPointer]) {
ncopy = ncopy.replace(a.slice(leftPointer, rightPointer + 1), '')
leftPointer += 2
rightPointer = leftPointer + 1;
if (leftPointer >= a.length || rightPointer >= a.length) {
break;
}
} else {
leftPointer++;
rightPointer++;
}
}
console.log(ncopy);
You can do this with a simple regex:
'aabbbcde'.replace(/(.)\1+/g, '')
Result:
'cde'
Snippet:
var a = 'aabbbcde';
var result = a.replace(/(.)\1+/g, '');
console.log(result);
'aabbccde'
.split('')
.reduce(
(acc, cur) => {
if (acc.indexOf(cur) !== -1) {
return acc.slice(acc.length);
}
return [...acc, cur];
}
)
.join('')
You can do it with a following recursive function:
const input = 'aabbccddeeffg';
function getResult(str) {
const newStr = str.match(/(.)\1*/g).filter(str => !((str.length % 2 === 0) && (str.split('').every((char,i,arr) => char === arr[0])))).join('');
return newStr === str ? newStr : getResult(newStr)
}
const result = getResult(input);
console.log(result);

How do I get Fibonacci numbers in an array?

Given input = [1,2,4] return [1,2], or if no fibonacci numbers return [], [1,1,2] should return [1,2];
I know you can check whether a number is in the fibonacci sequence with this code:
function isSquare(n) {
return n > 0 && Math.sqrt(n) % 1 === 0;
};
//Equation modified from http://www.geeksforgeeks.org/check-number-fibonacci-number/
function isFibonacci(numberToCheck)
{
// numberToCheck is Fibinacci if one of 5*n*n + 4 or 5*n*n - 4 or both
// is a perferct square
return isPerfectSquare(5*numberToCheck*numberToCheck + 4) ||
isPerfectSquare(5*numberToCheck*numberToCheck - 4);
}
But I don’t know how to implement it. Thanks.
Array.from(new Set(arr)) Removes duplicates from the original array
let newArr = []; Defining the new array
for ( let i = 0; i < arrD.length; i++ ) Loop every number of arrD, arrD[i] accesses a number in the array
if(fib(arrD[i])) { newArr.push(arrD[i]); } if the number is in the fibonacci sequence, fib(arrD[i]) will return true, and the number will be .pushed into the newArr
Using a for loop
let arr = [1,2,3,8,3,8];
let sqrt = (num) => { return num > 0 && Math.sqrt(num) % 1 === 0; };
let fib = (num) => { return sqrt(5 * Math.pow(num,2) + 4) || sqrt(5 * Math.pow(num,2) - 4); };
function fibArr(arr) {
arrD = Array.from(new Set(arr));
let newArr = [];
for ( let i = 0; i < arrD.length; i++ ) {
if(fib(arrD[i])) { newArr.push(arrD[i]); }
}
return newArr;
}
console.log(fibArr(arr));
OR using .filter
let arr = [1,2,3,8,3,8];
let sqrt = (num) => { return num > 0 && Math.sqrt(num) % 1 === 0; };
let fib = (num) => { return sqrt(5 * Math.pow(num,2) + 4) || sqrt(5 * Math.pow(num,2) - 4); };
function fibArr(arr) {
arrD = Array.from(new Set(arr));
let newArr = arrD.filter(function(arrD){
return fib(arrD);
})
return newArr;
}
console.log(fibArr(arr));

Serializing Array of Many Duplicates

So I have a series of arrays, each of which are 2500 long, and I need to serialize and store all them in very limited space.
Since I have many duplicates, I wanted to cut them down to something like below.
[0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0]
// to
[0x4,2,7,3x2,0x9]
I wrote a couple one-liners (utilising Lodash' _.repeat) to convert to and from this pattern, however converting to doesn't seem to work in most/all cases.
let serialized = array.toString().replace(/((?:(\d)+,?)((?:\2+,?){2,}))/g, (m, p1, p2) => p2 + 'x' + m.replace(/,/g, '').length);
let parsed = serialized.replace(/(\d+)x(\d+),?/g, (z, p1, p2) => _.repeat(p1 + ',', +p2)).split(',');
I don't know why it doesn't work. It may be due to some of the numbers in the array. Eye-balling, the largest one is 4294967295, however well over 90% is just 0.
What am I missing in my RegEx that's preventing it from working correctly? Is there a simpler way that I'm too blind to see?
I'm fairly confident with converting it back from the serialized state, just need a hand getting it to the state.
Straight forward and simple serialization:
let serialize = arr => {
const elements = [];
const counts = []
let last = undefined;
[0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0].forEach((el,i,arr)=>{
if (el!==last) {
elements.push(el);
counts.push(1);
} else {
counts[counts.length-1]++;
}
last = el;
})
return elements.map((a,i)=>counts[i]>1?`${a}x${counts[i]}`:a).join(",");
};
console.log(serialize([0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0]));
UPDATE
Pure functional serialize one:
let serialize = arr => arr
.reduce((memo, element, i) => {
if (element !== arr[i - 1]) {
memo.push({count: 1, element});
} else {
memo[memo.length - 1].count++;
}
return memo;
},[])
.map(({count, element}) => count > 1 ? `${count}x${element}` : element)
.join(",");
console.log(serialize([0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0]));
Pure functional deserialize:
const deserialize = str => str
.split(",")
.map(c => c.split("x").reverse())
.reduce((memo, [el, count = 1]) => memo.concat(Array(+count).fill(+el)), []);
console.log(deserialize("4x0,2,7,2x3,9x0"))
In order to avoid using .reverse() in this logic, I'd recommend to change serialization from 4x0 to 0x4
Try this
var arr = [0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0];
var finalArray = []; //array into which count of values will go
var currentValue = ""; //current value for comparison
var tmpArr = []; //temporary array to hold values
arr.forEach( function( val, index ){
if ( val != currentValue && currentValue !== "" )
{
finalArray.push( tmpArr.length + "x" + tmpArr[0] );
tmpArr = [];
}
tmpArr.push(val);
currentValue = val;
});
finalArray.push( tmpArr.length + "x" + tmpArr[0] );
console.log(finalArray);
Another version without temporary array
var arr = [0, 0, 0, 0, 2, 7, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var finalArray = []; //array into which count of values will go
var tmpCount = 0; //temporary variable to hold count
arr.forEach(function(val, index) {
if ( (val != arr[ index - 1 ] && index !== 0 ) )
{
finalArray.push(tmpCount + "x" + arr[ index - 1 ] );
tmpCount = 0;
}
tmpCount++;
if ( index == arr.length - 1 )
{
finalArray.push(tmpCount + "x" + arr[ index - 1 ] );
}
});
console.log(finalArray);
Do not use RegEx. Just use regular logic. I recommend array.reduce for this job.
const arr1 = [0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0]
const arr2 = ['0x4','2','7','3x2','0x9'];
const compact = arr => {
const info = arr.reduce((c, v) =>{
if(c.prevValue !== v){
c.order.push(v);
c.count[v] = 1;
c.prevCount = 1;
c.prevValue = v;
} else {
c.prevCount = c.prevCount + 1;
c.count[v] = c.count[v] + 1;
};
return c;
},{
prevValue: null,
prevCount: 0,
count: {},
order: []
});
return info.order.map(v => info.count[v] > 1 ? `${v}x${info.count[v]}` : `${v}`);
}
const expand = arr => {
return arr.reduce((c, v) => {
const split = v.split('x');
const value = +split[0];
const count = +split[1] || 1;
Array.prototype.push.apply(c, Array(count).fill(value));
return c;
}, []);
}
console.log(compact(arr1));
console.log(expand(arr2));
This is a typical reducing job. Here is your compress function done in just O(n) time..
var arr = [0,0,0,0,2,7,3,3,0,0,0,0,0,0,0,0,0],
compress = a => a.reduce((r,e,i,a) => e === a[i-1] ? (r[r.length-1][1]++,r) : (r.push([e,1]) ,r),[]);
console.log(JSON.stringify(compress(arr)));
since the motivation here is to reduce the size of the stored arrays, consider using something like gzip-js to compress your data.

Categories