I have two really long arrays containing "picture names" and "picture files". The first one represents the actual name of the pictures, while the second one is just the file name. For example:
picturenames[0] = '0 - zero';
picturenames[1] = '1 - one';
picturenames[2] = '1 o\'clock';
...
picturefiles[0] = 'numbers-zero.jpg';
picturefiles[1] = 'numbers-one.jpg';
picturefiles[2] = 'time-1.jpg';
...
I have about 1000 items in each array in several languages (the picture files are always the same). I'm "recycling" these arrays from the previous application to save some time and avoid rewriting everything anew.
Desirable functionality: using the user's input in a textbox I want to filter the picturenames array and then show the correspondant picturefiles image.
The issue I'm facing: when I filter the picturenames array I lose the index and I can't "reach" the picture file name.
This is the code I'm using to filter the picturenames array.
var matches = picturenames.filter(function(windowValue){
if(windowValue) {
return windowValue.indexOf(textToFindLower) >= 0;
}
});
What would be the best way to do this?
UPDATE: the solution proposed by Ahmed is the best one, but for time reasons and negligible performance issues I'm just using a for loop to search trough the array, as follows:
var matchesCounter = new Array();
for (i = 0; i < picturenames.length; i++) {
if (picturenames[i].indexOf(textToFindLower) >= 0) {
matchesCounter.push(i);
}
}
console.log(matchesCounter);
for (i = 0; i < matchesCounter.length; i++) {
console.log(picturenames[i]);
console.log(picturefiles[i]);
}
Try this:
const foundIndicies = Object.keys(picturenames).filter(pictureName => {
pictureName.includes(textToFindLower)
});
// reference picturefiles[foundIndicies[0]] to get the file name
Though, it would be far nicer to have both the name and the file in a single object, like so:
const pictures = [
{
name: '0 - zero',
file: 'numbers-zero.jpg',
},
{
name: '1 - one',
file: 'numbers-one.jpg',
}
];
const foundPictures = pictures.filter(picture => picture.name.includes('zero'));
if (foundPictures[0]) console.log(foundPictures[0].file);
You can add one property index during the filtering time, then later on you can use the index.
var matches = picturenames.filter(function(windowValue, index){
if(windowValue) {
windowValue.index = index;
return windowValue.comparator(textToFindLower) >= 0;// Need to define comparator function
}
});
Later on you can access by using like follows:
picturefiles[matches[0].index]
However, the solution will work on object, not primitive type string.
If your data type is string, then you have to convert as object and put the string as a property value like name. The snippet is given below:
var picturenames = [];
var picturefiles = [];
picturenames.push({name:'0 - zero'});
picturenames.push({name:'1 - one'});
picturenames.push({name:'1 o\'clock'});
picturefiles.push({name:'numbers-zero.jpg'});
picturefiles.push({name:'numbers-one.jpg'});
picturefiles.push({name: 'time-1.jpg'});
var textToFindLower = "0";
var matches = picturenames.filter(function(windowValue, index){
if(windowValue) {
windowValue.index = index;
return windowValue.name.indexOf(textToFindLower) >= 0;
}
});
console.log(matches);
I'm trying to write a vote counting function, I have an array of objects and each object has a property called currentVote which has a userId value. I want to find out which userID has the most votes. Using lodash this is what I got so far:
function countVotes(players) {
return new Promise(function(resolve, reject) {
//votes should be empty, filled it with some sample values
let votes = ['312139659792875521','360445341989863434', '312139659792875521','360445341989863435','1','9999999999999999999999'];
for (let i = 0, j = players.length; i < j; i++) {
votes.push(players[i].currentVote);
}
let tally = _.chain(votes)
.countBy()
.toPairs()
.sortBy(1).reverse()
.map(0)
.value()[0];
resolve(tally);
});
How can I pick a random value IF I have multiple userIds with the same number of votes. At the moment it seems that the smallest ID will always be picked?
Based on your question, I believe your object is as follow, I have used the array method sort to sort the array in descending and picked up the first element. Hope this helps.
let players = [{
"userId":1,
"currentVotes":2220
},
{
"userId":2,
"currentVotes":383830
},
{
"userId":3,
"currentVotes":6894740
},
{
"userId":4,
"currentVotes":6894740
},
{
"userId":5,
"currentVotes":1
}
];
function getHighestVoteByRandowm(players){
let arrSameVotes = [];
let i = 0;
do{
arrSameVotes.push(players[i]);
temp = players[i].currentVotes;
i++;
}while(players[i].currentVotes == temp);
let rndTill = arrSameVotes.length - 1;
let rndVal = Math.round(Math.random() * rndTill);
return arrSameVotes[rndVal];
}
function sortVotes(a,b){
return b.currentVotes - a.currentVotes;
}
let highestVotesPlayer = getHighestVoteByRandowm(players.sort(sortVotes));
console.log(highestVotesPlayer);
You could use _.shuffle and _.first. Maybe something like:
_.chain(votes).countBy()
.groupBy() // added this to get a list of all the ones that have matching vote counts
.toPairs()
.sortBy(0)
.reverse()
.first() // most votes
.last() // get the user ids
.shuffle() // randomize order
.first() // get whatever is first
.value()
I am trying to write some javascript in Zapier which will read two dates and then return an array of all dates between those dates in such a way that they can then be used to create multiple dated records in Airtable (a database). From the Zapier help it says that if you return an array of objects then the following steps will be processed for each.
I have managed to get code which returns the data I wan but it can't be correct because if I try to create the database records only one is created - with all the dates in (so it will only work if output to a text field - not a date). Here's my code attempt:
var fromDate = new Date(inputData.from);
var toDate = new Date(inputData.to);
var output =[];
var i = 1;
do {
var useDate = new String(fromDate.toISOString())
output.push(useDate);
console.log(fromDate);
fromDate.setDate(fromDate.getDate() + 1);
i++
}
while (fromDate <= toDate);
console.log(output);
return{output};
The subsequent step does see the output variable - but it is treated as one value as I said above.
Does anyone have any ideas?
Thanks Juan
That sorted it - or at least it did after removing the return - here is the working code:
var fromDate = new Date(inputData.from);
var toDate = new Date(inputData.to);
var output =[];
var i = 1;
do {
var useDate = new String(fromDate.toISOString())
var dateObject = {};
dateObject.date = useDate;
output.push({dateObject});
fromDate.setDate(fromDate.getDate() + 1);
i++
}
while (fromDate <= toDate);
It looks like you're returning an object, not an array of objects:
return{output};
Also, your do/while statement is creating an array of strings, not objects. In your do block, instead of pushing the useDate string to the output array, you should construct a simple object and push that to the output array.
So instead of pushing '2016-09-28T00:00:00.000Z' each time the loop runs, you should push something like {date: '2016-09-28T00:00:00.000Z'}.
Your do block should look something like this:
do {
var useDate = new String(fromDate.toISOString());
var dateObject = {};
dateObject.date = useDate;
output.push(dateObject);
fromDate.setDate(fromDate.getDate() + 1);
i++
}
This way, output will be an array of objects:
[
{
"date": "2016-09-28T00:00:00.000Z"
},
{
"date": "2016-09-29T00:00:00.000Z"
},
{
"date": "2016-09-30T00:00:00.000Z"
}
]
I have an array inside an object in my database that accumulates duplicate objects over time (a drawback of working with the unreliable Instagram API). I'm attempting to routinely purge this array of duplicates and replace it with the cleaned up array. I'm having a difficult time understanding why the below code run on my node server does not work. The trimArray function works perfectly, but the 'photos' array within my MongoDB object is never updated.
// Takes in an array and outputs an array with only unique objects
function trimArray(bloatedArray) {
var seen = {};
var trimmedArray = [];
var len = bloatedArray.length;
var j = 0;
for(var i = 0; i < len; i++) {
var imageLink = bloatedArray[i].link;
var image = bloatedArray[i];
if(seen[imageLink] !== 1) {
seen[imageLink] = 1;
trimmedArray[j++] = image;
}
}
return trimmedArray;
}
Event.find( { $and: [{latitude: latitude}, {radius: distance}] },
function(err,event){
if (err) {
} else {
var array = event[0].photos;
Event.update( { $and: [{latitude: latitude}, {radius: distance}] },
{ 'photos': trimArray(array) }
);
}
}
);
I think update will simply update existing records, not remove them. It looks for items in the returned array and updates them accordingly. If you want to use your trimArray, you'll have to empty the collection and then reinsert the trimArray results (terrible idea).
Instead, you should set your collection up correctly to not store duplicates in the first place. You'll want to set up a unique index, and then you'll never have to purge.
See the docs for details.
db.things.ensureIndex({'photos.make_some_key' : 1}, {unique : true, dropDups : true})
I'm new to javascript, and I'm having trouble figuring out how to loop through some code so that it will basically create an array that I can then pass on to my plot variable.
I'm not really sure where to start. Right now I have a chunk of code that takes my first dataset (dataOne) and formats it so that it can go into my plot variable. I basically need to do that three more times for the other data sets - hoping to include the example.getDataSets function to loop through somehow.
Is there a good way to do this?
Here is my code:
script.js
var example = {};
example.data = {
dataOne: {data: [{"date":1333238400000,"data":23},{"date":1333324800000,"data":37},{"date":1333411200000,"data":49},{"date":1333497600000,"data":54},{"date":1333584000000,"data":30},{"date":1333670400000,"data":19},{"date":1333756800000,"data":15},{"date":1333843200000,"data":19},{"date":1333929600000,"data":145}]},
dataTwo: {data: [{"date":1335830400000,"data":63},{"date":1335916800000,"data":77},{"date":1336003200000,"data":66}]},
dataThree: {data: [{"date":1341100800000,"data":24},{"date":1341187200000,"data":50},{"date":1341273600000,"data":43},{"date":1341360000000,"data":39},{"date":1341446400000,"data":56},{"date":1341532800000,"data":66}]},
dataFour: {data: [{"date":1333238400000,"data":71},{"date":1333324800000,"data":46},{"date":1333411200000,"data":66},{"date":1333497600000,"data":73},{"date":1333584000000,"data":105},{"date":1333670400000,"data":84}]}
}
example.getDataSets = function(){
return ['dataOne', 'dataTwo', 'dataThree', 'dataFour']
}
example.getSeries = function(month){
return example.data[month]
}
example.processData = function(data){
var newData = []
for(var i = 0; i < data.length; i++){
newData.push([data[i].date, data[i].data])
};
return newData;
}
My script in the HTML page:
$.getScript("script.js")
.done(function() {
var b = example.getSeries('dataOne');
var d = example.processData(b.data);
// first correct the timestamps - they are recorded as the daily
// midnights in UTC+0100, but Flot always displays dates in UTC
// so we have to add one hour to hit the midnights in the plot
for (var i = 0; i < d.length; ++i)
d[i][0] += 60 * 60 * 1000;
var plot = $.plot($("#placeholder"), [d] , options);
Any suggestions are much appreciated!
Loop over the value returned from .getDataSets, too
var sets = example.getDataSets(), set_i = 0, // get list of sets
b = {}, d = [], i = 0, plot; // set-up vars
for(; set_i < sets.length; set_i++){ // loop over each set
b = example.getSeries( sets[ set_i ] ); // get your set
d = example.processData(b.data);
for (i = 0; i < d.length; ++i)
d[i][0] += 60 * 60 * 1000;
plot = $.plot($("#placeholder"), [d] , options);
// ... etc with plot
}
If you want them all in one array before plotting, use concat on another array (call it d_total or something) and then in the set loop, d_total = d_total.concat( d );, then plot outside loop
I'm assuming you want to process each of
var b = example.getSeries(X);
where X is, in turn, 'dataOne', 'dataTwo', 'dataThree', 'dataFour'?
If so, you'll be looking for something like this:
// see below for where example.ordering is suggested
for (var i in example.ordered) {
var month = example.ordered[i];
var b = example.getSeries(month);
var d = example.processData(b.data);
... further processing with month, b, d.
}
The getDataSets() is fine for yielding your 'months' in what must be proper order for you. My only concern is that you have the list of months in two places. The array you have is necessary for ordering the months, because you cannot extract the 'month names' from example.data and expect them to be in the same order (keys are essentially stored randomly due to hashing).
The qualification would be if your keys are sortable, but the keys you have here are not. Of course, if you're building the pair of structures from the same source, then storing the data in the associated array (example.data object) along with a separate array to indicate ordering is both common and acceptable. Ideally you'd pair these two into yet another object so they can be handled as a team.
Since your array of ordered months is literally 'lost' in a function, I would suggest you add something like
example.ordering = [ ..... ]
and even better, push the months onto the end of that list in the same order they are put into the hash. I would be using a helper function to store the data:
example.ordering = []; // initially empty
example.storeSet = function (month, dataList) {
example.ordering.push(month);
example.data[month] = { data : dataList };
}
....
// now store the data
example.storeSet('dataOne', [{"date":1333238400000,"data":23}, ....]);
example.storeSet('dataTwo', [{"date":1335830400000,"data":63}, ....]);
example.storeSet('dataThree', [{"date":1341100800000,"data":24}, ....]);
example.storeSet('dataFour', [{"date":1333238400000,"data":71}, ....]);
Of course my code is untested (of course!) but it looks right, and I'm sure you can fix any stupid mistakes I might have made.
I am new and understand your frustration when you have sat and looked and still cannot find the answer. However, what I think you are looking for is something like this:
for (example.data=dataOne;example.data<dataFour;example.data=example.data+increment)
{
code to be executed
}
or maybe even recursively but I am not the best at that but below is an standard example
function recurs(p1) {
p1--;
if (p1 < 0) return // exit condition
setTimeout("recurs("+p1+")",1);
}