I have a array of string.
let arr=["robin","rohit","roy"];
Need to find all the common character present in all the strings in array.
Output Eg: r,o
I have tried to create a function for above case with multiple loops but i want to know what should be the efficient way to achive it.
Here's a functional solution which will work with an array of any iterable value (not just strings), and uses object identity comparison for value equality:
function findCommon (iterA, iterB) {
const common = new Set();
const uniqueB = new Set(iterB);
for (const value of iterA) if (uniqueB.has(value)) common.add(value);
return common;
}
function findAllCommon (arrayOfIter) {
if (arrayOfIter.length === 0) return [];
let common = new Set(arrayOfIter[0]);
for (let i = 1; i < arrayOfIter.length; i += 1) {
common = findCommon(common, arrayOfIter[i]);
}
return [...common];
}
const arr = ['robin', 'rohit', 'roy'];
const result = findAllCommon(arr);
console.log(result);
const arr = ["roooooobin","rohit","roy"];
const commonChars = (arr) => {
const charsCount = arr.reduce((sum, word) => {
const wordChars = word.split('').reduce((ws, c) => {
ws[c] = 1;
return ws;
}, {});
Object.keys(wordChars).forEach((c) => {
sum[c] = (sum[c] || 0) + 1;
});
return sum;
}, {});
return Object.keys(charsCount).filter(key => charsCount[key] === arr.length);
}
console.log(commonChars(arr));
Okay, the idea is to count the amount of times each letter occurs but only counting 1 letter per string
let arr=["robin","rohit","roy"];
function commonLetter(array){
var count={} //object used for counting letters total
for(let i=0;i<array.length;i++){
//looping through the array
const cache={} //same letters only counted once here
for(let j=0;j<array[i].length;j++){
//looping through the string
let letter=array[i][j]
if(cache[letter]!==true){
//if letter not yet counted in this string
cache[letter]=true //well now it is counted in this string
count[letter]=(count[letter]||0)+1
//I don't say count[letter]++ because count[letter] may not be defined yet, hence (count[letter]||0)
}
}
}
return Object.keys(count)
.filter(letter=>count[letter]===array.length)
.join(',')
}
//usage
console.log(commonLetter(arr))
No matter which way you choose, you will still need to count all characters, you cannot get around O(n*2) as far as I know.
arr=["robin","rohit","roy"];
let commonChars = sumCommonCharacters(arr);
function sumCommonCharacters(arr) {
data = {};
for(let i = 0; i < arr.length; i++) {
for(let char in arr[i]) {
let key = arr[i][char];
data[key] = (data[key] != null) ? data[key]+1 : 1;
}
}
return data;
}
console.log(commonChars);
Here is a 1 liner if anyone interested
new Set(arr.map(d => [...d]).flat(Infinity).reduce((ac,d) => {(new RegExp(`(?:.*${d}.*){${arr.length}}`)).test(arr) && ac.push(d); return ac},[])) //{r,o}
You can use an object to check for the occurrences of each character. loop on the words in the array, then loop on the chars of each word.
let arr = ["robin","rohit","roy"];
const restWords = arr.slice(1);
const result = arr[0].split('').filter(char =>
restWords.every(word => word.includes(char)))
const uniqueChars = Array.from(new Set(result));
console.log(uniqueChars);
This is what I've tried and it seems like I'm on the right path but I've been trying to tweak this algorithm for a while and I can't figure out what I'm doing wrong. Here is my code so far:
const getThem = async () => {
const format2 = 'YYYY/MM/DD';
const obj = {};
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].tests.length; j++) {
for (let z = 0; z < channel.length; z++) {
if (data[i].tests[j] === channel[z].id) {
const dateTime = moment(channel[z].start).format(format2);
const dateTime2 = moment(channel[z].end).format(format2);
const dateList = getDateArray(new Date(dateTime), new Date(dateTime2));
if (Date.parse(dateTime) > Date.parse('2019-11-15') || Date.parse(dateTime) < Date.parse('2019-11-04')) {
break;
}
if (!channel[z].end) {
// eslint-disable-next-line operator-assignment
obj[dateTime] += (1 / data.length);
} else {
for (let k = 0; k < dateList.length; k++) {
if (!obj.hasOwnProperty(dateList[k])) {
obj[dateList[k]] = 1 / data.length;
} else {
obj[dateList[k]] += (1 / data.length);
}
}
}
}
}
}
}
setDates(Array.sort(Object.keys(obj)));
setValues(Object.values(obj));
};
Check my answer. The approach is simple. First we loop through all the testsResponse data and get the minimum and maximum dates then we iterate through each day from min to max date. For each current day we check the test ids in testsResponse data and then we filter the channels data from the tests array in channelsResponse data and then finally we take the % by the filtered channels data and total channels response data and push it in the results array. The only catch here is that it will push all the dates between minimum test.start and maximum test.end dates both inclusive. If you want to exclude the dates for which testIds is empty then just before the results.push() check if testIds.length is not 0. Here is the getThem():
// given channelsResponse & testsResponse
const getThem = () => {
// get min and max dates
let max='';
let min=new Date().toISOString();
testsResponse.forEach(test => {
min=test.start && min.localeCompare(test.start)>0?test.start:min;
max=test.end && max.localeCompare(test.end)<0?test.end:max;
});
min=new Date(min.substr(0,10)+'T00:00:00.000Z');
max=new Date(max.substr(0,10)+'T00:00:00.000Z');
let results = [];
// loop from min date to max date
for(var i=min; i<=max; i.setDate(i.getDate()+1)) {
let p=0;
let d=i.toISOString().substr(0,10);
// get test ids within the current date
const testIds = testsResponse.filter(t => d.localeCompare((t.start+'').substr(0,10))>=0 && d.localeCompare((t.end+'').substr(0,10))<=0).map(t => t.id);
// get channels where above test ids were found
const channels = channelsResponse.filter(c => c.tests.some(t => testIds.includes(t)));
// calculate %
p=Math.round(channels.length*100.0/channelsResponse.length);
// push data for current date to results
results.push({date: i.toISOString(), utilizationPercentage: p})
}
return results;
};
console.log(getThem());
// [{"date":"2019-11-04T00:00:00.000Z","utilizationPercentage":14},{"date":"2019-11-05T00:00:00.000Z","utilizationPercentage":86},{"date":"2019-11-06T00:00:00.000Z","utilizationPercentage":71},{"date":"2019-11-07T00:00:00.000Z","utilizationPercentage":43},{"date":"2019-11-08T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-09T00:00:00.000Z","utilizationPercentage":29},{"date":"2019-11-10T00:00:00.000Z","utilizationPercentage":29},{"date":"2019-11-11T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-12T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-13T00:00:00.000Z","utilizationPercentage":57},{"date":"2019-11-14T00:00:00.000Z","utilizationPercentage":43},{"date":"2019-11-15T00:00:00.000Z","utilizationPercentage":43}]
Check the demo code here: https://ideone.com/L2rbVe
To avoid iteration over your inputs several times, getting a bad time complexity, I would suggest using Maps and Sets, so you can find related information efficiently.
I kept your function getDateArray. As you didn't provide its source, I reproduced it. But you may want to use your own:
const channelsResponse = [{id: 372,name: 'Channel 01',lab: 'Fullerton',tests: [3, 4, 7, 8],},{id: 373,name: 'Channel 02',lab: 'Fullerton',tests: [1, 2, 5, 6],},{id: 374,name: 'Beta Channel',lab: 'Fullerton',tests: [],},{id: 472,name: 'Channel 01',lab: 'Queens',tests: [9, 11, 12, 13],},{id: 473,name: 'Channel 02',lab: 'Queens',tests: [15, 17, 19],},{id: 474,name: 'Channel 03',lab: 'Queens',tests: [21, 22, 24, 25],},{id: 475,name: 'Channel 04',lab: 'Queens',tests: [26, 27, 28, 29, 30],},];
const testsResponse = [{id: 1,start: '2019-11-05T11:05:00Z',end: '2019-11-05T13:05:00Z',},{id: 2,start: '2019-11-06T11:05:00Z',end: '2019-11-06T13:05:00Z',},{id: 3,start: '2019-11-04T11:05:00Z',end: '2019-11-04T13:09:00Z',},{id: 4,start: '2019-11-04T17:00:00Z',end: '2019-11-05T09:32:00Z',},{id: 5,start: '2019-11-11T11:05:00Z',end: '2019-11-12T13:05:00Z',},{id: 6,start: '2019-11-12T14:05:00Z',end: '2019-11-15T13:05:00Z',},{id: 7,start: '2019-11-07T11:05:00Z',end: '2019-11-08T13:05:00Z',},{id: 8,start: '2019-11-08T15:05:00Z',end: '2019-11-08T15:35:00Z',},{id: 9,start: '2019-11-05T09:05:00Z',end: '2019-11-08T12:05:00Z',},{id: 11,start: '2019-11-08T12:35:00Z',end: '2019-11-08T13:35:00Z',},{id: 12,start: '2019-11-08T17:00:00Z',end: '2019-11-11T10:00:00Z',},{id: 13,start: '2019-11-11T12:00:00Z',end: null,},{id: 15},{id: 17,start: '2019-11-05T17:00:00Z',end: '2019-11-06T10:00:00Z',},{id: 19,start: '2019-11-06T12:00:00Z',end: '2019-11-06T13:22:00Z',},{id: 21,start: '2019-11-05T09:05:00Z',end: '2019-11-06T12:05:00Z',},{id: 22,start: '2019-11-08T12:35:00Z',end: '2019-11-08T13:35:00Z',},{id: 24,start: '2019-11-11T17:00:00Z',end: '2019-11-15T10:00:00Z',},{id: 25,start: '2019-11-15T12:00:00Z',},{id: 26,start: '2019-11-05T09:05:00Z',end: '2019-11-06T12:05:00Z',},{id: 27,start: '2019-11-07T12:35:00Z',end: '2019-11-07T13:35:00Z',},{id: 28,start: '2019-11-08T17:00:00Z',end: '2019-11-11T10:00:00Z',},{id: 29,start: '2019-11-12T12:00:00Z',end: '2019-11-12T14:00:00Z',},{id: 30,start: '2019-11-13T12:00:00Z',end: '2019-11-13T14:00:00Z',},];
function getDateArray(start, end) {
if (!start || !end) return [];
let date = new Date(start.slice(0,11) + "00:00:00Z");
let last = Date.parse(end.slice(0,11) + "00:00:00Z");
let dates = [date.toJSON()];
while (+date != last) {
date.setDate(date.getDate()+1);
dates.push(date.toJSON());
}
return dates; // array of date-strings
}
// Create two maps for faster retrieval
let mapTestToDates = new Map(testsResponse.map(( { id, start, end }) => [id, getDateArray(start, end)]));
let allDates = [...new Set([...mapTestToDates.values()].flat())].sort();
let mapDateToChannels = new Map(allDates.map(date => [date, new Set]));
// Main data collection loop
for (let channel of channelsResponse) {
for (let test of channel.tests) {
for (let date of mapTestToDates.get(test)) {
mapDateToChannels.get(date).add(channel);
}
}
}
// Finally calculate the percentages
let result = Array.from(mapDateToChannels.entries(), ([date, channels]) =>
({ date, utilizationPercentage: Math.round(channels.size * 100 / channelsResponse.length) })
);
console.log(result);
For this problem, the function accepts an array of strings and returns an object. Keys are supposed to be the number of characters in a string and the value is supposed to be how many time a string with that amount of characters occurred.
I thought I was going somewhere and then I got stuck. I'd appreciate some help on this, I've tried googling it a million different ways but no luck. Thank you!
The result is supposed to look like : characterCount(['apple', 'berry', 'cherry']) // {5:2, 6:1}
function characterCount(arr){
var newObj = {};
var valueMax = 0;
var currentValue = 0;
for(var i=0; i < arr.length; i++){
var key = arr[i].length;
for(var z=0; z < arr.length; z++){
if (arr[z].length === arr[i].length){
currentValue ++;
if (currentValue > valueMax){
valueMax = currentValue;
}
}
}
newObj.key = "valueMax";
}
return newObj;
}
Look at the Array.prototype.reduce function. This allows you to take an array, iterate over each value, and return a new, reduced value.
function characterCount(arr) {
return arr.reduce((counts, str) => ({
...counts,
[str.length]: (counts[str.length] || 0) + 1
}), {});
}
const counts = characterCount(['apple', 'berry', 'cheery']);
console.log(counts);
Alternatively, you could use Object.assign instead of spreading the accumulator object.
function characterCount(arr) {
return arr.reduce((counts, str) => Object.assign(counts, {
[str.length]: (counts[str.length] || 0) + 1
}), {});
}
const counts = characterCount(['apple', 'berry', 'cheery']);
console.log(counts);
You could just reduce the array to accomplish the output
function characterCount( array ) {
return array.reduce( (agg, cur) => {
// get the length of the current item
const len = cur.length;
// increase the value of the key index with one (if none exist, start with 0)
agg[len] = (agg[len] || 0) + 1;
// return the next value for the iteration
return agg;
}, {});
}
console.log( characterCount(['apple', 'berry', 'cherry']) );
Using reduce is arguably better but here is a more straightforward approach.
function characterCount(arr) {
const countByLength = {};
for (let item of arr) {
countByLength[item.length] = (countByLength[item.length] || 0) + 1;
}
return countByLength;
}
console.log(characterCount(['apple', 'berry', 'cherry']));
This question already has answers here:
Array.fill(Array) creates copies by references not by value [duplicate]
(3 answers)
Closed 3 years ago.
my function has to take 2 arrays and if one of the arrays is shorter than the other it needs to fill in the blanks with nulls.
so i could do this easier now that i think about it but i would really like to know what i have missed.
the specific part of my code is the nested forEach loops i cant understand that when i invoke my function like this
fillSquare([1,2,3],[1,2,3,4,5])
I get [[1,2,3,4,5],[1,2,3,4,5]] instead of [[1,2,3,null,null][1,2,3,4,5]]
const fillSquare = arr => {
const maxArrayLength = Math.max(
...arr.map(arr => {
return arr.length;
})
);
let arrayMatrix = new Array(arr.length).fill(
new Array(maxArrayLength).fill(null)
);
arr.forEach((arry, mainIndex) => {
arry.forEach((item, subIndex) => {
console.log(mainIndex, "<--main", "sub-->", subIndex, "=", item);
arrayMatrix[mainIndex][subIndex] = item;
});
});
console.log(arrayMatrix);
return arrayMatrix;
};
When debugging, it seems:
let arrayMatrix = new Array(arr.length).fill(
new Array(maxArrayLength).fill(null)
);
// arrayMatrix[1] == arrayMatrix[0] => true
is only creating 1 array instance. setting 1 value on one sets it on both.
heres how to fix your issue
let arrayMatrix = new Array(arr.length).fill(0).map( _ => new Array(maxArrayLength).fill(null));
this is my version - now immutable
function fillSquare(arr) {
let clone = [...arr]
let maxDepth = arr.reduce( (c, subarr) => c = Math.max(c, subarr.length), 0)
clone.forEach((subarr, index) => {
let len = clone[index].length;
clone[index].length = maxDepth;
clone[index].fill(null, len, maxDepth);
})
return clone;
}
the import notes are you can set the length and fill the gaps. Also check out reduce if you need.
const fillSquare = function(arr){
let minLengthArr = arr[0];
let maxLength = arr[1].length;
if(arr[1].length < arr[0].length){
minLengthArr= arr[1];
maxLength = arr[0].length;
}
let itemsToPush = maxLength - minLengthArr.length;
for(let i=0;i<itemsToPush;i++){
minLengthArr.push(null);
}
return arr;
}
var r = fillSquare([[1,2,3],[1,2,3,4,5]]);
console.log(r);
I have an array of Date() objects in javascript and I want to count the number of events on each day.
Here is an example:
What I have is:
Array [ Date 2014-12-04T10:30:20.000Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z ]
What I want is:
Array [{date: '2014-12-04', counts: 1}, {date: '2014-12-05', counts: 3}]
Thanks a lot!
Max
Basic answer:
var arr = [], // fill it with array with your data
results = {}, rarr = [], i, date;
for (i=0; i<arr.length; i++) {
// get the date
date = [arr[i].getFullYear(),arr[i].getMonth(),arr[i].getDate()].join("-");
results[date] = results[date] || 0;
results[date]++;
}
// you can always convert it into an array of objects, if you must
for (i in results) {
if (results.hasOwnProperty(i)) {
rarr.push({date:i,counts:results[i]});
}
}
These can be made much easier with lodash functions, and Array.forEach() in ES5
You much better off having a simple object with the keys as the date and the value as the count. I've added a simple pad function that prefixes a zero where the number is a single digit as per your output requirements.
function pad(n) {
return n.toString().length == 1 ? '0' + n : n;
}
function getCount(arr) {
var obj = {};
for (var i = 0, l = arr.length; i < l; i++) {
var thisDate = arr[i];
var day = pad(thisDate.getDate());
var month = pad(thisDate.getMonth() + 1);
var year = thisDate.getFullYear();
var key = [year, day, month].join('-');
obj[key] = obj[key] || 0;
obj[key]++;
}
return obj;
}
getCount(arr); // Object { 2014-04-12: 1, 2014-05-12: 3 }
DEMO
I came across the same issue and found this solution which uses Map()
`
calc = (obj) => {
const orders = []
const dates_map = new Map()
//iterate through all the objects inside the orders array
orders.forEach(order => {
// format and get the date
const date = new Date(order.created_at).toLocaleDateString('en-GB')
//check if the date key exists in the Map() and save it in a temp
const temp = dates_map.get(date) || false
// if it does not exist
if (temp) {
// clone the object
const previous = {...temp}
// increase counter
previous.count += 1
dates_map.set(date, previous)
}else{
//create new object to avoid overwriting
const result = {}
result.count = 1
dates_map.set(date, result)
}
})
console.log(dates_map)
}
And this is the output
Output: Map(3) {
'08/05/2021' => { count: 2 },
'09/05/2021' => { count: 1 },
'11/05/2021' => { count: 2,}
}
`