Frequency of a string in an array of strings
Create a function you are given a collection of strings and a list of queries. For every query there is a string given. We need to print the number of times the given string occurs in the collection of strings.
Examples:
Input :
a[] = [wer, tyu, uio]
b[] = [wer, wer, tyu, oio, tyu]
Output : [2 2 0]
Explanation :
a[0] appears two times in b[]
function occur (a,b) {
let count = [];
for (var i = 0; i<= a.length ; i++) {
for (var j = 0;j<= b.length; j++) {
if (a[i]==b[j]) {
return count[i] = count[i]++;
}
}
}
}
console.log(occur(["aaaa","cc" ,"dd"],["aaaa","dd"]));
You should use some form of hash to only iterate once through the collection of strings, before considering any of the queries. An ES6 Map can used for that purpose.
Then per entry in the hash you would have the frequency count (counted with reduce).
One idea would to not just return that hash, but return a function that consults the hash and returns the corresponding frequency or 0 if it is not in that hash.
Here is how that would look:
// Returns function that can answer queries for the given collection of strings
function freq(strings) {
const counts = strings.reduce((map, s) => map.set(s, (map.get(s)||0)+1), new Map);
return s => counts.get(s) || 0;
}
// Sample call. The 3 queries are fed into the function returned by freq
const results = ["wer", "tyu", "uio"].map(freq(["wer", "wer", "tyu", "oio", "tyu"]));
console.log(results);
Related
Here is some Javascript code that creates a 2-dimension array and fills each cell with a random number.
// populate 2D array with integers
const row = 5, col = 7
let pic = new Array(row).fill(0).map(item => (new Array(col).fill(0)))
for (let x = 0; x < row; x++) {
for (let y = 0; y < col; y++) {
pic[x][y] = Math.floor((Math.random() * 90) + 10)
}
}
console.log(JSON.stringify(pic))
I'm looking for a more 'elegant' solution. My questions:
Is there a way to use the fill so that I can put in my target values? Then I can be finished with creating the array in one line.
How do I use a double .map to populate the 2D array, instead of a double for loop?
Is there a way to assign the output from the map / for loops directly into a variable? Then I don't need a separate create statement.
What is the best way to reshape an array? For example, changing a 1-by-10 array into a 5-by-2 array.
Is there a way to enforce a type? For instance the first dimension is a string, 2nd is an integer, etc.
Feel free to add your own definition of elegance. One of the things I'm looking for is a flexible approach that can also work with 3D arrays.
You could take a nested Array.from with a length and a mapping function.
const
fn = () => Math.floor(Math.random() * 5),
row = 5,
col = 7,
array = Array.from({ length: row }, () => Array.from({ length: col }, fn));
array.forEach(a => console.log(...a));
Is there a way to use the fill so that I can put in my target values? Then I can be finished with creating the array in one line.
No, fill is not that flexible. There is Array.from(iterable, callback) but I find it cumbersome and it is slow. I'd rather write that utility quickly
function array(n, callback){
const output = Array(n);
for(let i=0; i<n; ++i) output[i] = callback(i);
return output;
}
How do I use a double .map to populate the 2D array, instead of a double for loop?
map creates a new Array, by calling the callback function for each item on the current Array. You can abuse it to mutate the Array that is iterating. You can ignore the returnes Array and abuse it as forEach; but then map simply is the wrong tool.
var newMatrix = Array(5).fill().map(() => Array(7).fill().map(() => Math.random()));
the fill part is necessary, because Array(length) creates a sparse Array of that length and map only iterated defined indices (even if they contain undefined)
Is there a way to assign the output from the map / for loops directly into a variable? Then I don't need a separate create statement.
I'm not sure what you mean, because you already do that here let pic = new Array(row).fill(0).map(...)
What is the best way to reshape an array? For example, changing a 1-by-10 array into a 5-by-2 array.
function array(n, callback) {
const output = Array(n);
for (let i = 0; i < n; ++i) output[i] = callback(i);
return output;
}
function toGroupsOf(n, data) {
return array(Math.ceil(data.length / n), i => data.slice(n * i, n * (i + 1)));
}
const oneByTen = [array(10, v => v)];
console.log(oneByTen);
const twoByFive = toGroupsOf(5, oneByTen.slice().flat());
console.log(twoByFive);
Is there a way to enforce a type? For instance the first dimension is a string, 2nd is an integer, etc.
No, not in JS. btw. everything but the last dimension will be Arrays, not String.
But check out Typescript.
Feel free to add your own definition of elegance. One of the things I'm looking for is a flexible approach that can also work with 3D arrays.
// a general purpose function to create n-dimensional arrays.
// m(...dimensions, (...indices) => value)
function m(...args) {
return args.reduceRight((cb, length) => (...indices) => {
const output = Array(length);
for (let i = 0; i < length; ++i)
output[i] = cb(...indices, i);
return output;
})();
}
let data = m(5,7, () => Math.floor(Math.random() * 90 + 10));
console.log(data);
// 4-dimensions
console.log(m(2,3,4,5, Math.random));
// a 5x5 identity-matrix
console.log(m(5,5, (i,j) => i === j? 1: 0).join("\n"));
I'm a user of strongly typed languages like Scala, where for instance, you could never store a string in an integer variable. I find the laissez faire of Javascript difficult.
I have mixed opinions on that. I loved the way that static types and compile-time errors found little mistakes/oversights back when I learned (in AS3). Nowadays and with Typescript I often find Typescript to be too opinionated and find myself thinking f off compiler, I know/mean what I'm writing here and prefer the flexibility of JS. On the other hand, I still enjoy the assistance that comes from the IDE knowing what Objects I'm currently dealing with and what properties/methods they provide.
Heavily inspired by: https://stackoverflow.com/a/53859978/9758920
const row = 5, col = 7;
let pic = [...Array(row)].map(r => [...Array(col)].map(c => ~~(Math.random()*90)+10));
console.log(pic)
This should work.
const randomNumber = Math.floor((Math.random()*90)+10);
const randomMatrix = (row, col) => {
return new Array(row).fill(randomNumber).map(item => (new Array(col).fill(randomNumber)))
}
console.log(randomMatrix(5, 7))
Try the snippet below. initializeArray accepts parameters for width, height and a value for each cell.
const initialize2DArray = (w, h, val = null) =>
Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
console.log(initialize2DArray(3, 3, 0)) // 3x3 matrix filled with zeros
If you prefer a N-dimension array, try the snippet below:
const initializeNDArray = (val, ...args) =>
args.length === 0
? val
: Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
console.log(initializeNDArray(-1, 3, 3, 3))
I'm a beginner at programming and looking for some help with multidimensional arrays (thank you in advance for your help!) I'm trying to complete a Kata on Code Wars, specifically "xD-Arrays for dummies." The prompt wants the user to return a multidimensional array based on an unknown set of arguments.
For example, the function dim( 3,3,"x" ), should return, [['x','x','x'],['x','x','x'],['x','x','x']]. First, creating a single array with 3 'x' (i.e. [x, x, x]), and then 3 more arrays to store the first array (i.e. [[x, x, x], [x, x, x], [x, x, x]]). To pass the kata you will be passed an unknown amount of arguments.
I've tried creating an iterative function, and settled on recursion, since we don't know the amount of arguments we might receive.
This is my code thus far...
function dim() {
// Create an array from the arguments given when the function is called
var args = Array.from(arguments);
// Store the first element as value
var val = args.pop();
// Store the second element which we will repeat for our first array
var d1 = args.pop();
var xDarr = [];
for (var x = 0; x < d1; x++) {
if (typeof val == 'function') {
xDarr.push(val());
} else {
xDarr.push(val);
};
};
if (args.length >= 1) {
var reversedArg = args.reverse();
return getMatrix(reversedArg, xDarr);
} else {
// if we are only passed 2 arguments, such as (dim (2, true)), return xDarr
return xDarr;
};
};
function getMatrix(arr, item) {
// dimArr equals the first array we have created, example: "[x, x, x]"
var dimArr = item;
for (var i = 0; i < arr.length; i++) {
// iterate through every other element in our args
var finalMatrix = [];
genMatrix(arr[i]);
dimArr = finalMatrix;
// here, the recursion function to return finalMatrix
function genMatrix(num) {
if (num === 1) {
return dimArr;
} else {
return finalMatrix.push(dimArr, genMatrix(num - 1))
};
};
console.log("Updated dimArr: " + dimArr)
};
return dimArr;
};
The function seems to work with arguments that are four elements long, such as dim( 2,2,2,0 ), but for odd arguments, such as dim( 3,3,"x" ), my function returns number(s) at the end of my array. dim( 3,3,"x" ) produces the following result: [ [ 'x', 'x', 'x' ], [ 'x', 'x', 'x' ], [ 'x', 'x', 'x' ], 2 ]. I've tried researching using Mozilla but can't figure out what that "2" at the end is. Thank you so much for your help!
The number is inserted by the recursive call in the function getMatrix:
return finalMatrix.push(dimArr, genMatrix(num - 1))
The return value here is what push returns, and push returns the new length of the finalMatrix array. This means that if the recursive call also gets to execute this line, you actually pass a number as second argument to push. And push will push whatever arguments you pass to it, hence the number that is pushed here.
You can solve this in different ways, but since the initial call of genMatrix doesn't actually use the returned value, you could just avoid returning anything, and just perform the recursion and push separately:
function genMatrix(num) {
if (num) {
finalMatrix.push(dimArr);
genMatrix(num - 1);
};
};
Note that there are simpler ways to generate a matrix. You could omit this function all together and in getMatrix do:
for (var i = 0; i < arr.length; i++) {
dimArr = Array(arr[i]).fill(dimArr);
}
The function should only pass three parameters no more -- no less:
function genTable(rows, cells, content) {...
rows: Number of rows
cells: Number of cells per row (also can be considered as columns)
content: A value to be placed at every cell
It takes two for loops to generate a 2D array (aka table and matrix)
An empty array is declared which represents the table -- the outer array that contains all of the sub-arrays.
|🡄 table array 🡆|
[ [...], [...], [...], [...] ]
The outer loop creates an empty array which represents a row -- the sub-arrays within the outer array (table)
[ [...], [...], [...], [...] ]
row row row row
The inner loop pushes the content [3rd parameter] into the array.
[ [content, content, content],
[content, content, content], [content, content, content], [content, content, content] ]
Once inner loop iterates Nc times (Nc = cells [2nd parameter]) the next loop of the outer loop pushes the full array into the table array then creates the next array (row).
This process is repeated Nr times (Nr = rows [1st parameter])
Once the outer loop is complete the table array is returned.
function genTable(rows, columns, content) {
const table = [];
for (let r = 0; r < rows; r++) {
let rowArray = [];
for (let c = 0; c < columns; c++) {
rowArray.push(content);
}
table.push(rowArray);
}
return table;
}
console.log(JSON.stringify(genTable(4, 6, 'X')));
console.log(JSON.stringify(genTable(8, 2, 'Y')));
console.log(JSON.stringify(genTable(2, 10, 'Z')));
I'm trying to learn JavaScript well and am practicing rebuilding some underscore functions. I'm trying to rebuild zip using map where there is an arbitrary number of arguments. Here is the solution I came up with, with pluck. I know that the underscore implementation itself uses _pluck, which internally uses Map, so I wanted to see if it was possible to do this with map...
_.zip = function() {
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
//create and return an array that is as long as the longestArray:
var zipped = Array(longestArray.length);
// you want to push each element from each array onto an array with the length of the longestArray.
for (var i = 0; i < longestArray.length; i++) {
zipped[i] = _.pluck(argumentsArray, i)
};
return zipped;
}
I'm stuck on what to return inside the map function below. I know I have to do some sort of a loop up to the length of the longest element, since the returned array should be that long. How would I do that inside map? Or, should I just do two for loops instead of trying to use map?
zip = function() {
//get the longest input argument:
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
//trying to use map here:
return map(argumentsArray, function(val){
return ?
})
};
console.log(zip([1, 2, 4], [1]))
// returns [[1, 1],[2, undefined],[4, undefined]]
Below I have attached what should be a working copy of your original implementation without the use of pluck using only maps.
var zip = function() {
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
return longestArray.map(function(value, index, array) {
return argumentsArray.map(function(val, i, arr) {
return val[index];
});
});
};
The outer map over longestArray acts solely as a looping mechanism so it would be better suited to use a for-loop instead.
The inner loop maps over the array of arguments passed in and, using the current index of the outer map, returns the ith element of each argument array. Since map already returns a new array, each iteration of the inner map will return an array containing the ith elements for each argument array.
Below is another implementation using a for loop and a map.
function zip() {
//turn args into an array
var argumentsArray = Array.prototype.slice.call(arguments);
var returnArr = [];
//get length of longest array
var length = argumentsArray.reduce(function (prev, curr) {
//starter val is 0, if curr array is longer replace with its length
return (prev >= curr.length) ? prev : curr.length;
}, 0);
//push an array of the ith element of each of the argument arrays
//into the return array
for (var i = 0; i < length; i++) {
returnArr.push(argumentsArray.map(function (val) {
return val[i];
}));
}
return returnArr;
}
Also note that instead of sorting to find the largest array, I reduce over the array lengths to find and return the longest length.
Since js sort is in-place it will potentially change your arguments array order. Your returned array of zipped elements will then be ordered by their original array lengths. Doing it this way they will instead be in the order that the argument arrays were passed in. But both are valid zip implementations depending on what you need.
Hope this helps!
I'm currently trying to make a search function that searches an array for a string and returns the index of the location in the array for which it matches the string.
Ex:
Array: [1,2,3,4,5,2,3,1,6,5,2]
Search input: 3
Output:
2
6
Search input: 2
Output:
1
5
10
Currently i have it outputting only 1 value by using
document.getElementById("result").innerHTML=
But I want it to return multiple results
If you write your own function, you should be able to return an array of indices:
function indicesOf(input, value) {
var indices = new Array();
for (var i = 0; i < input.length; i++) {
if (input[i] == value)
indices.push(i);
}
return indices;
}
Then you can combine the array values and put them into the result location, as suggested by #AnthonyGrist:
document.getElementById('result').innerHTML = indicesOf(input, value).join(', ');
I'm not sure if that's what you're after, but if you want to return all objects with a given selector from DOM (as opposed to acting on and returning filtered javascript array) then you could use document.querySelectorAll(<your_selector_here>) - more information at MDN here
You can do this
var arr = [1,2,3,4,5,2,3,1,6,5,2];
arr.map(function(x, i){
return x == 3 ? i : null;
}).filter(Number); // get indexes
The above maps and filters out the index. Then it is simply a matter of joining it
document.getElementById("result").innerHTML= arr.join("<br />");
I want a function, subtract, that will take two arrays, and return all of the elements in array 1 that are not in array 2.
what is the fastest that this can be implemented in js? Is it o(n)?
Another option, faster O(n) time, but double memory (still linear), is to create your own hashmap implementation.
Create a hash function. Do a loop through one array and hash all elements. Store (hash, object) pair in another array, call it hash array. Now loop through array 2, and hash each element. Let the hash be the position in hash array, so you can see if you have a collision. If you have a collision check if the object in hash array is the same as the object in current array (that you're looping over).
Here's a hash table implementation (using a javascript object as the hash) that is more than 100 times faster (in Chrome) with larger arrays than the brute force lookups using indexOf().
function subtract3(one, two) {
var hash = {}, result = [], i, len;
// fill hash with members of second array for easy lookup
for (i = 0, len = two.length; i < len; i++) {
hash[two[i]] = true;
}
// cycle through first array and find ones that are not in two
for (i = 0, len = one.length; i < len; i++) {
if (!(one[i] in hash)) {
result.push(one[i]);
}
}
return(result);
}
Here's a jsperf test comparing this option with a couple other options: http://jsperf.com/array-subtraction
You cannot generically solve this for O(n) unless you want to restrict your arrays to objects that can be serialized to strings
function substract(one, two) {
var result = []
for (var i = 0, len = one.length; i < len; i++) {
var value = one[i]
if (two.indexOf(value) === -1) {
result.push(value)
}
}
return result
}
Or if you want to use array iterators
function substract(one, two) {
return one.filter(function (value) {
return two.indexOf(value) === -1
})
}