I have the following function to check for duplicates;
function hasDuplicates(array) {
return (new Set(array)).size !== array.length;
}
I use this to check if someone has not provided two of the same items to sell from his or her inventory, cause we won't allow him or her getting twice the amount of money he or her should.
It worked for a while but then I think someone who meant harm came in and breached it somehow. I've been testing for a while now and found that I can bypass this sytem by having my array like the following (ids of my inventories);
var array = [312, 329, 932]; //normal > should bypass
var array = [333, 333, 333]; //not normal > can't bypass
but then if you do this it allows you to bypass;
var array = [333, '333/', '333//'];
is there any way I can solve this quickily?
Edit
Database query that looks up the data anyways even if its provided as 333// strings.
database.query('SELECT * FROM `inventories` WHERE `id` = ' + database.pool.escape(id), function(err, row){
array.every(n => Number.isInteger(n))
Just ensure that everything is a number in the array.
You can do something like the following with hash,
and use regex to remove the special characters and leave it with a number only, (casting it to Number is also recommended).
var array = ['333//', 212, '333/'];
var hash = {};
array.forEach(num => {
if(!Number.isInteger(num)) {
num = Number(num.replace(/[^\w\s]/gi, ''));
}
if(!hash[num]) {
hash[num] = num;
}
})
var newArray = Object.values(hash);
console.log(newArray);
Related
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);
So I'm working on an agent that's supposed get data from MongoDB, iterate through it, and then find the keys which have the same values, and sort that list in ascending order. Basically, find out how many repetitions there are in the documents from Mongo, and then sort it.
So I've gotten to the part where I get repetitions in the data, and count them, but I'm stuck with getting the ascending order part.
The code for getting documents out of mongodb and processing it is as follows.
function matchRoomAndAgent() {
var url = 'mongodb://192.168.10.10:27017';
MongoClient.connect(url, function (err, db) {
db.collection("whiteboardRooms").find({}).toArray(function (err, res) {
var roomsArray = [];
var count = {};
var temp_count = {};
if (err) {
throw err;
}
db.close();
// roomsArray.push(res);
for (var i = 0; i < res.length; i++) {
roomsArray.push(res[i]);
// console.log('agentId: '+ res[i][agentId].agentId);
}
// console.log(roomsArray);
for (var i = 0; i < 15; i++) //supposed to use length of roomsArray
{
var currentAgent = roomsArray[i].agentId;
for (var j = 0; j < 15; j++)
{
if (roomsArray[j].agentId == currentAgent)
{
count[j] = (count[j] || 0) + 1;
temp_count[j] = count[j];
}
}
console.log(temp_count);
}
Also please find attached, a sample pic of the mongodb documents.
MongoDB Documents
Please let me know if you require more information, and I'll do my best to get it. I'm kind of a noob at programming. Sorry!
Thanks in advance for your help :)
At some point you might want to limit the material being grouped, for example by lastUpdateTime between two timestamps and you don't want to drag all that out of the DB just to throw it away. Here's the general shape of the solution:
db.foo.aggregate([
{$match: {agentID: {$ne: " "}}} // guessing this is noise so filter out
// other $match could be used here to further shrink the data...
,{$group: {_id:"$agentID", n:{$sum:1}}}
,{$match: {n: {$gt:1}}} // ignore non-dupes
,{$sort: {_id: 1}} // and finally sort.
]);
So I've figured out the answer to my own problem. Its pretty much got nothing to do with MongoDB.
I basically had an array called roomsArray which contained objects. I used groupBy and map to project these objects to a format I wanted, and then used sort as I would an array, using its length to get the count.
I should have used groupBy() and map() with sort() to get the values I needed.
var groupBy = function (array, key) {
return array.reduce(function(acc,val){
(acc[val[key]] = acc[val[key]] || []).push(val);
return acc;
}, {});
};
var result = groupBy(roomsArray, 'agentId');
// console.log(result);
var mapped = Object.keys(result).map(function(x){
return { agentId : x, rooms: parseInt(result[x].length)}
});
// console.log(mapped);
var sorted = mapped.sort((a,b) => a.rooms - b.rooms);
console.log(sorted);
I have a comma-separated string being pulled into my application from a web service, which lists a user's roles. What I need to do with this string is turn it into an array, so I can then process it for my end result. I've successfully converted the string to an array with jQuery, which is goal #1. Goal #2, which I don't know how to do, is take the newly created array, and remove all characters before any array item that contains '/', including '/'.
I created a simple work-in-progress JSFiddle: https://jsfiddle.net/2Lfo4966/
The string I receive is the following:
ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC
ABCD/ in the string above can change, and may be XYZ, MNO, etc.
To convert to an array, I've done the following:
var importUserRole = 'ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC';
var currentUserRole = importUserRole.split(',');
Using console.log, I get the following result:
["ABCD", "ABCD/Admin", "ABCD/DataManagement", "ABCD/XYZTeam", "ABCD/DriverUsers", "ABCD/RISC"]
I'm now at the point where I need the code to look at each index of array, and if / exists, remove all characters before / including /.
I've searched for a solution, but the JS solutions I've found are for removing characters after a particular character, and are not quite what I need to get this done.
You can use a single for loop to go through the array, then split() the values by / and retrieve the last value of that resulting array using pop(). Try this:
for (var i = 0; i < currentUserRole.length; i++) {
var data = currentUserRole[i].split('/');
currentUserRole[i] = data.pop();
}
Example fiddle
The benefit of using pop() over an explicit index, eg [1], is that this code won't break if there are no or multiple slashes within the string.
You could go one step further and make this more succinct by using map():
var importUserRole = 'ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC';
var currentUserRole = importUserRole.split(',').map(function(user) {
return user.split('/').pop();
});
console.log(currentUserRole);
You can loop through the array and perform this string replace:
currentUserRole.forEach(function (role) {
role = role.replace(/(.*\/)/g, '');
});
$(document).ready(function(){
var A=['ABCD','ABCD/Admin','ABCD/DataManagement','ABCD/XYZTeam','ABCD/DriverUsers','ABCD/RISC'];
$.each(A,function(i,v){
if(v.indexOf('/')){
var e=v.split('/');
A[i]=e[e.length-1];
}
})
console.log(A);
});
You could replace the unwanted parts.
var array = ["ABCD", "ABCD/Admin", "ABCD/DataManagement", "ABCD/XYZTeam", "ABCD/DriverUsers", "ABCD/RISC"];
array = array.map(function (a) {
return a.replace(/^.*\//, '');
});
console.log(array);
var importUserRole = 'ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC';
var currentUserRole = importUserRole.split(',');
for(i=0;i<currentUserRole.length;i++ ){
result = currentUserRole[i].split('/');
if(result[1]){
console.log(result[1]+'-'+i);
}
else{
console.log(result[0]+'-'+i);
}
}
In console, you will get required result and array index
I would do like this;
var iur = 'ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC',
arr = iur.split(",").map(s => s.split("/").pop());
console.log(arr);
You can use the split method as you all ready know string split method and then use the pop method that will remove the last index of the array and return the value remove pop method
var importUserRole = ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC';
var currentUserRole = importUserRole.split(',');
for(var x = 0; x < currentUserRole.length; x++;){
var data = currentUserRole[x].split('/');
currentUserRole[x] = data.pop();
}
Here is a long way
You can iterate the array as you have done then check if includes the caracter '/' you will take the indexOf and substact the string after the '/'
substring method in javaScript
var importUserRole = 'ABCD,ABCD/Admin,ABCD/DataManagement,ABCD/XYZTeam,ABCD/DriverUsers,ABCD/RISC';
var currentUserRole = importUserRole.split(',');
for(var x = 0; x < currentUserRole.length; x++){
if(currentUserRole[x].includes('/')){
var lastIndex = currentUserRole[x].indexOf('/');
currentUserRole[x] = currentUserRole[x].substr(lastIndex+1);
}
}
UPDATE: this is NOT a question on javascript alone, but related to the javascript implementation on the MarkLogic platform.
As the title of this question points out it is about the specific behaviour of the ValueIterator that is returned by the xdmp.userRoles() function.
I am trying to see if a user has a certain role in MarkLogic Security database, therefor I have done this :
declareUpdate();
var pid = '7610802';
// TODO validate that user can do this
var spo = 'scc-proj-' + pid + '-owner';
var spm = 'scc-proj-' + pid + '-member';
var spam = 'scc-proj-' + pid + '-adv-member';
// we need the security db Ids of these roles
var spoId = xdmp.role(spo);
var spamId = xdmp.role(spam);
var acceptedRoleIds = [spamId,spoId];
// get roleIds from sec db for this user
var userRoleIds = xdmp.userRoles('scc-user-1');
// map ValueIterator to array
var userRoleIdsArray = userRoleIds.toArray();
Now the userRoleIdsArray holds ids as unnsigned long like this:
[
"1088529792688125909",
"1452323661308702627",
"10258509559147330558",
"10161853410412530308",
"6677433310138437512",
"12773061729023600875",
"7482704131174481508",
"3191093315651213021", <<<<< this is the one!!!
"5126952842460325403",
"7089338530631756591",
"15520654661378671735",
"13041542794130379697"
]
Now indexOf() gives me -1 aka not found
userRoleIdsArray.indexOf(3191093315651213021);
OR
userRoleIdsArray.indexOf("3191093315651213021");
Gives :
-1
While
userRoleIdsArray[7]==3191093315651213021;
Gives :
true
What am I missing here? Is this not the way to use indexOf() ?
UPDATE >>> Stuff below was 'on-the-side' but turns out to be distracting from the above core question. The behaviour below is answered by #DaveCassel's comment.
btw on the created array acceptedRoleIds it is even more strange:
acceptedRoleIds.indexOf(spoId);
works
acceptedRoleIds.indexOf(3191093315651213021);
does not?
Could this large number error in javascript be relevant?
You want to find a String, not a number. Use: userRoleIdsArray.indexOf("3191093315651213021");
This works:
var array = [
"1088529792688125909",
"1452323661308702627",
"10258509559147330558",
"10161853410412530308",
"6677433310138437512",
"12773061729023600875",
"7482704131174481508",
"3191093315651213021",
"5126952842460325403",
"7089338530631756591",
"15520654661378671735",
"13041542794130379697"
];
var n = array.indexOf("13041542794130379697");
document.write(n);
output: 11
The mismatch is that ValueIterator.toArray() returns an array of Values (Value[]). When you call .indexOf, you're passing in a string or an unsignedLong rather than a value. Because the types don't match, .indexOf() doesn't report a match.
You can solve the problem by iterating through the loop. Note that I use the '==' operator rather than '==='; the type conversion is needed.
// get roleIds from sec db for this user
var userRoleIds = xdmp.userRoles('my-user');
// map ValueIterator to array
var userRoleIdsArray = userRoleIds.toArray();
var target = 15520654661378671735;
var index = -1;
for (var i in userRoleIdsArray) {
if (userRoleIdsArray[i] == target) {
index = i;
}
}
index
This might seems a very newbie sort of question, but I am struggling with this as of now and seek some help.
Here is a example array in JavaScript
var SelectedFilters = ["[size:12:12]","[size:12:12]","[size:13:13]","[size:14:14]", "[color:14:14]","[color:14:14]","[type:14:14]","[type:14:14]"];
Now I wish to remove certain items from this array based on a search term, now the search term contains only a part of string such as
var searchTerm1 = 'size'
var searchTerm2 = 'color'
I have already tried the following code, but its not working:
var i = SelectedFilters.indexOf(searchTerm1);
if (i != -1)
{
SelectedFilters.splice(i, 1);
}
I have also tried running to through for loop, to iterate on all items, but again search failed as its not able to match 'size' OR 'color'
What I am looking: if searchterm1 is used, the resulted output will be like:
["[color:14:14]","[color:14:14]","[type:14:14]","[type:14:14]"];
and in case of searchterm2 is used the resulted output should be:
["[size:12:12]","[size:12:12]","[size:13:13]","[size:14:14]","[type:14:14]","[type:14:14]"];
It would be great if anyone can solve this puzzle, I am also trying to find a solution in the meantime.
Your attempt didn't work because .indexOf() on an Array looks for an exact match.
Since according to your question and comment you need to mutate the original Array, you should loop over the array and test each string individually and then call .splice() every time you find one that needs to be removed.
var SelectedFilters = ["[size:12:12]","[size:12:12]","[size:13:13]","[size:14:14]", "[color:14:14]","[color:14:14]","[type:14:14]","[type:14:14]"];
var searchTerm1 = 'size'
var searchTerm2 = 'color'
for (var i = SelectedFilters.length-1; i > -1; i--) {
if (SelectedFilters[i].startsWith(searchTerm1, 1)) {
SelectedFilters.splice(i, 1)
}
}
document.querySelector("pre").textContent =
JSON.stringify(SelectedFilters, null, 2)
<pre></pre>
The loop used above goes in reverse. This is important since every time we do a .splice(), the array gets reindexed, so if we went forward, we would end up skipping over adjacent items to be removed.
The .startsWith() method checks if the string starts with the given search term. I passed the second parameter a value of 1 so that it starts searching on the second character.
You can use filter method of array
var searchTerm = "size";
SelectedFilters = SelectedFilters.filter(function(val){
return val.indexOf( searchTerm ) == -1;
});
You can do it with Array#filter,
var searchTerm1 = 'size';
var result = SelectedFilters.filter(v => !v.includes(searchTerm1));
console.log(result); //["[color:14:14]","[color:14:14]","[type:14:14]","[type:14:14]"];
If you want to alter the original array then do,
var SelectedFilters = ["[size:12:12]", "[size:12:12]", "[size:13:13]", "[size:14:14]", "[color:14:14]", "[color:14:14]", "[type:14:14]", "[type:14:14]"];
var searchTerm1 = 'size',cnt = 0, len = SelectedFilters.length - 1;
while (cnt <= len) {
if (SelectedFilters[len - cnt].includes(searchTerm1)) SelectedFilters.splice(len - cnt, 1);
cnt++;
}
console.log(SelectedFilters);
DEMO