From the name of the question this might seem like an easy task, but im a beginner. What I need to do is compare a string (user input, I already have it), with a list of words. Basically if the user inputs bluuexel I still want to have the program to interpret it as blue (im actually making a bot to censor words and just entering random stuff is a common strategy to bypass censors). I was going to sort and delete duplicates but then I realized that "ass" would become "as" and this strategy wouldnt be as applicable.
For analyzing strings, you may use String.prototype.includes to see if a substring is located in a string or other options such as Regex for exact matches. Many approaches may be applied, but this example may get you started. String.prototype.includes
For replacing other strings, you something such as String.prototype.replace. String.prototype.replace
Since you also tagged this post under Node.js, to receive user input from the command prompt. Use may use the Node.js readline module. Readline
Beware of the comparison item.value == search may cause unexpected type coercion also. That is why we are using ====.
Note
Your question is a little broad, but it seems you are trying to compare strings against other strings. It would help to provide some code so we get a sense of what you are trying to accomplish.
var items = [{
value: "one"
},
{
value: "bluuexel"
}
]
// Accept a search string term variable
unique = (search) => {
// Iterate through the object items
// Some: Determines whether the specified callback function
// returns true for any element of an array.
return items.some(item => {
// Return if item.value is equal to the search string, beware of
// Comparison item.value == search may cause unexpected type
// coercion. So we use ===
return item.value === search
});
};
// Accept a search string term variable
contains = (search) => {
// Iterate through the object items
// Some: Determines whether the specified callback function
// returns true for any element of an array.
return items.some(item => {
// Includes: Returns true if searchString
// appears as a substring of the result of converting
// this object to a String, at one or more positions that
// are greater than or equal to position; otherwise, returns false.
// Return if item.value contains equal to the search string
return item.value.includes(search)
});
};
console.log('Unique:', unique('bluuexel'), '=> bluuexel');
console.log('Contains:', contains('bluu'), '=> bluu');
console.log('Contains:', contains('bluu2'), '=> bluu2');
console.log('Unique:', unique('one'), '=> one');
console.log('Unique:', unique('one2'), '=> one2');
Now for removing words from an array or duplicates, also many other approaches. But here is a simple example.
We also make use of the Spread syntax (...) allows an iterable such as an array expression or string to be expanded in short terms. Spread
The Set constructor lets you create Set objects that store unique values of any type, whether primitive values or object references. Set
// Defined list of an array of words
let words = ['bluuexel', 'bluuexel2', 'bluuexel'];
// ... Spread operator to iterate over array elements in array "words"
console.log('Removed (Duplicates)', words);
let removed = [...new Set(words)];
// Output unique only words, from new array named "removed"
console.log('Removed (Non Duplicates)', removed);
Putting it together to remove some banned words and also duplicates.
// Filtering words and duplicates
// Word List
let words = [ 'one',
'one',
'two',
'two2',
'ass',
'as']
// Banned Words
let banned = ['ass']
// Contains word, accepts a string and a list as an array
contains = (search, list) => {
// Determine if the list has a string
return list.some(item => {
return item.includes(search)
});
};
// Function for filtering, and removing duplicates and banned words
function filter() {
// Remove duplicates first, update word list
words = [...new Set(words)];
// Iterate through banned word list
banned.forEach((word) => {
// Output that banned word was found
console.log('Found Banned (Word):', word)
if (contains(word, words)) {
// Update final word list
words.splice(words.indexOf(word), 1);
}
})
}
console.log('Previous Results', words)
// Run filter function
filter()
// Output results
console.log('Final Results', words)
Related
I have two arrays one of it is having user id and another one is having user ids. Those arrays are as follows.
1)The array which is having user id.
data[key].effective_employees Which is eaqual to [2].
Now I have another array which is having numbers of employee ids which is as follows.
data2[0].id Which is eaqual to [2,22,21].
And now I am trying to see whether the array two has number in array 1 I am using the following logic to see whether it is working or not.
if ((/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees)))) {
let isElem = _.contains(returnStackFilterd, value);
if (isElem == false) {
returnStackFilterd.push(value);
}
} else {
returnStackFilterd = _.without(returnStackFilterd, value);
}
But this is showing true for the number 2 if the array two is having 22. Psudo code of what is happening with it is as follows.
if([2]is in[22,21]){ it is printing true} I want false here as the number two is not in the second array. The second array contains 22 and 21 which is not eaqual to 2
How do i solve this problem? The above psudo code should print false.
Let's break down your test expression and see why it doesn't work.
First off, we know that data[key].effective_employees is [2]. data2[0].id might be [2, 22, 21] or [22, 21]. If I'm understanding your question correctly, you want the whole test expression to return true in the first case and false in the second case.
Rebuilding your test expression from the bottom up, the innermost expression we find is this:
data2[0].id.toString()
This is a string with the value '2,22,21' or '22,21', depending on which case we are talking about. Next, you wrap this string in an array:
[data2[0].id.toString()]
So now we have ['2,22,21'] or ['22,21']. Note the quotes; in either case, it is an array with a single element that is a string.
Next, you take the intersection of this array with data[key].effective_employees, which we know is [2]:
_.intersection([data2[0].id.toString()], data[key].effective_employees)
So this expression is effectively
_.intersection(['2,22,21'], [2])
or
_.intersection(['22,21'], [2])
You are always taking the intersection of two arrays, where the first contains a single string and the second contains a number. They can't have any elements in common, so that's always going to produce an empty array ([]).
Finally, you test whether that empty array matches a regular expression:
/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees))
// is effectively the same as
/^\d+$/.test([])
Regular expressions are supposed to be matched against a string, not an array. JavaScript is very lenient in situations like these and will coerce the value you're passing to a string. That means that the value [] is first converted to the empty string '' before being matched to the regular expression /^\d+$/. The empty string does not contain any digits, so this test always returns false.
This is why your test doesn't work as intended. However, let's take a few steps back, because you seem to be doing many things you don't need to do. Why convert arrays to strings (and then back to array)? Why match against a regular expression, if you just want to know whether two arrays have elements in common?
The following, simpler expression will give you the elements that data[key].effective_employees and data2[0].id have in common:
_.intersection(data[key].effective_employees, data2[0].id)
This will evaluate to either [2] or [], depending on whether data[key].effective_employees contains the number 2 or not.
I suggest saving the result of this expression to a variable, because it makes your code easier to read. Let's call it commonIds:
const commonIds = _.intersection(data[key].effective_employees, data2[0].id)
Now you can formulate different conditions, based on what exactly you want this intersection to be like. My impression is that you just want it to be nonempty (i.e., at least one element in common). In that case, you can compare its length to zero:
if (commonIds.length > 0) {
// code for when there is an overlap
} else {
// code for when there is no overlap
}
As a final note, I recommend assigning your base expressions data[key].effective_employees and data2[0].id to variables as well. Again, this makes your code more readable, and it also ensures that you need to change only one line of code if those base expressions change. Putting it all together:
const key = 'x';
const data = { [key]: {
effective_employees: [2],
}};
const data2 = [{
id: [2, 22, 21],
}];
const userId = data[key].effective_employees;
const employeeIds = data2[0].id;
const commonIds = _.intersection(userId, employeeIds);
if (commonIds.length > 0) {
console.log('userId appears in employeeIds');
} else {
console.log('userId does not appear in employeeIds');
}
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
If data[key].effective_employees is the number 2, and data2[0].id is the array [2, 22, 21], the expression to test whether data2[0].id contains data[key].effective_employees is:
data2[0].id.includes(data[key].effective_employees)
From your original question, data2[0].id.toString() coerces the array to a string 2,22,21, which is no use to you. You also do not need to use Underscore for this.
My task is:
Implement the function duplicateStudents(), which gets the variable
"students" and filters for students with the same matriculation
number. Firstly, project all elements in students by matriculation
number. After that you can filter for duplicates relatively easily. At
the end project using the following format: { matrikelnummer:
(matrikelnummer), students: [ (students[i], students[j], ... ) ] }.
Implement the invalidGrades() function, which gets the variable "grades"
and filters for possibly incorrect notes. For example, in order to
keep a manual check as low as possible, the function should determine
for which matriculation numbers several grades were transmitted for
the same course. Example: For matriculation number X, a 2. 7 and a 2.
3 were transmitted for course Y. However, the function would also take
into account the valid case, i. e. for matriculation number X, once a
5,0 and once a 2,3 were transmitted for course Y.
In this task you should only use map(), reduce(), and filter(). Do not
implement for-loops.
function duplicateStudents(students) {
return students
// TODO: implement me
}
function invalidGrades(grades) {
return grades
.map((s) => {
// TODO: implement me
return {
matrikelnummer: -1/* put something here */,
grades: []/* put something here */,
};
})
.filter((e) => e.grades.length > 0)
}
The variables students and grades I have in a separate file. I know it might be helpful to upload the files too, but one is 1000 lines long, the other 500. That’s why I’m not uploading them. But I hope it is possible to do the task without the values. It is important to say that the values are represented as an array
I'll give you an example of using reduce on duplicateStudents, that's not returning the expected format but you could go from there.
const duplicateStudents = (students) => {
const grouping = students.reduce((previous, current) => {
if (previous[current.matrikelnummer]) previous[current.matrikelnummer].push(current); // add student if matrikelnummer already exist
else previous[current.matrikelnummer] = [current];
return previous;
}, {});
console.log(grouping);
return //you could process `grouping` to the expected format in here
};
here's preferences for you:
map
filter
reduce
Currently I iterate through a set of linkedObjects to to search for an isMatch. This test looks to see if element.id is present in the array obj.resource_ids if it is then we add the printable-string from the matching appointmentObj to an array in printStr.
The problem comes because value.resource_uniqueids could be an array containing many ids but my test only ever finds one.
Somehow I need to match all the ids in value.resource_uniqueids. - It might be the case that I need to add a new appointmentObj for each value.resource_uniqueids and then concatenate each equivalent printable-string
I hope this makes sense. How do I add a new ${currentMatch.printable-string} for each match of value.resource_uniqueids
Thanks !
_.forEach(appointmentObj, (value,i) => {
// value.resource_uniqueids is always an array, most of the time it only has one element
// but sometimes it can have more than one which means we only match one below in isMatch function
_.set(appointmentObj[i], 'resource_ids', value.resource_uniqueids );
_.set(appointmentObj[i], 'printable-string', `${value.title}, ${moment(value.created_at).format( 'Do MMMM YYYY')}` );
});
linkedObjects.forEach((element, index) => {
let isMatch = appointmentObj.find((obj) => {
return _.includes(obj.resource_ids,element.id);
});
if(isMatch) {
linkedObjects[index]['content']['printstring'] = `${currentMatch.printable-string}`;
}
});
The problem comes because value.resource_uniqueids could be an array
containing many ids but my test only ever finds one.
Array.prototype.find() returns a single matched element from within an array. Use Array.prototype.filter() if expected result is more than one matched result from within the iterated array.
I have a structure in MongoDB that have different amounts of items in an array called "items". To make the search, I am using the following command, which first turns the contents into a string, as in this.items there is a different structure depending on the object:
db.getCollection('docs').find.('JSON.stringify(this.items[0].value).toLowerCase().indexOf("text")!=-1')
My problem is that as I do not know the amount of items that each document has, I would have to use a wildcard as this.items[*].value, but it does not work.
Does anyone know any solution, or have another idea for this?
You can use the $elemMatch (https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/)
db.docs.find({items: {$elemMatch: {value: {$regex : "text"}}}});
So this query will find all documents with an item in the items array that contain the string "text" in the value property, after this operation you can count how much items the document has.
You can use dot notation of items.value to target the value field of all items elements, and a regular expression to perform the case-insensitive sub-string match:
db.getCollection('docs').find({ 'items.value': /text/i })
You can iterate each document and apply the indexOf, something like this..
var cursor = db.getCollection('docs').find({}); // get all docs
var newOut = []; // new array of items if match with some condition
while ( cursor.hasNext() ){ // iterate all docs
var doc = cursor.next(); // get the document in focus
doc.items.forEach(function(item){ // iterate the items of doc.items
if ( item.toLowerCase().indexOf("text") !== -1 ) // check if text exists in array
newOut.push(item); // add to new array
});
};
printjson(newOut);
I'm using YDN-DB (an abstraction on top of IndexedDB) as a local database. I have an object store called 'conversations', and in that store, there's an index called 'participants' where there is a string containing id's for different users in the conversation. For example:
Example Conversation #1:
id: 1234343434353456,
participants: '171e66ca-207f-4ba9-8197-d1dac32499db,82be80e2-2831-4f7d-a8d7-9223a2d4d511'
Example Conversation #2:
id: 4321343434356543,
participants: 'd7fa26b3-4ecc-4f84-9271-e15843fcc83f,171e66ca-207f-4ba9-8197-d1dac32499db'
To try to perform a partial match on an index, I tried using ydn-db-fulltext as a solution. The full text catalog looks like this:
{
name: 'participants',
lang: 'en',
sources: [
{
storeName: 'conversations',
keyPath: 'participants',
weight: 1
}
]
}
I see that the catalog is generated, but there seems to be a problem doing exact matches. For example, if I query using only part of the key in the participants index, I get back a primary key from the catalog:
db.search('participants', 'd7fa26b3').done(function(results) {
if(results.length == 0) console.debug('No results found...');
console.debug(results); // there is 1 object here!
var primaryKey = results[0].primaryKey; // primaryKey exists!
});
However, when using any value past the '-', the search request returns 0 results:
db.search('participants', 'd7fa26b3-4ecc-4f84-9271-e15843fcc83f').done(function(results) {
if(results.length == 0) console.debug('No results found...');
console.debug(results); // there are 0 objects in the array
var primaryKey = results[0].primaryKey; // primaryKey throws undefined since there are 0 results!
});
This makes sense, when reading the documentation, in that '-' and '*' are reserved characters that remove a phrase and match a prefix respectively:
Query format is free text, in which implicit and/or/near logic operator apply for each token. Use double quote for exact match, - to subtract from the result and * for prefix search.
I tried putting double quotes inside the single quotes, using only double quotes, and also escaping all of the '-' characters with a backslash, but none of these seem to work.
So the question is how does one perform a match in an index where the string contains '-' characters?
Have you try db.search('participants', '"d7fa26b3"').
BTW, you are using full text search that is not suppose to do. You have to tokenize your string and index them manually.
If you store the participants field of your object as an array, then you can use the multi-entry flag to the createIndex method called on the participants field, and probably do what you want.
The number of items in the participants property of the object is mutable. When you update an object in the store and it has a different number of items in the partic property, then the index is automatically updated as a result (just like any other index). If you add an item to the prop, then restore (put/override/cursor.update) the object in the store, the index updates.
It helps to review the basics of how a multi-entry index works. You can do this with vanilla js, without a framework, and certainly without full-text searching.