Javascript program to check if a prompt character is in Multidimensional array - javascript

I have a multidimensional array, where I'd like to check if a value is in it.
I tried the code below but it didn't work as intended
How do i check if username is in my multidimensional array?
let matrix = [
['Lol'],
['MyName'],
['Matrix']
];
let username = prompt('Enter Username')
if (matrix.includes(username)) {
alert('YESSS')
} else {
alert('no')
}
console.log(username)

There are a variety of JavaScript idioms to perform this task.
One option is to flatten the array before running include such as the example Hassam Imam posted.
matrix.flat().includes(username)
Issues will arise however depending on how much data is stored in the multidimensional array.
Another option would be to what Konrad Linkowski suggested and leverage some.
matrix.some(array => array.includes(username))
This has a performance increase as it will stop after finding the first case that matches the provided criteria, but the result is boolean. If you just want to know if the value exists I would recommend this solution.
If you wish to know where in the matrix an element is you will want to use find instead of some as it will provide you the index in which it was found.
matrix.find(arr => array.includes(username));
Though this could get quite complex depending on how many dimensions the array has.
Let me know if you have any questions or would like to stub out what this solution may look like.

Related

Check if a field has been modified with angular 6 and firestore

I have a form for editing a user details, where it should check if the user has make modification if not then don't make changes.
Currently am using if to check which is working but I still feel is not effective way for this, because I have multiple fields which have to check each of them which makes the code repetitive and huge.
if (f.value.first_name) {
this.user.firstName = f.value.first_name;
}
I have tried using elvis operator but it's not working for me
this.user.firstName ? this.user.firstName :f.value.first_name;
Is there any other effective way to do this?
You can loop through each form controls and check if they are dirty (modified).
Object.keys(f.controls).forEach((key: string) => {
if (f.get(key).dirty) {
this.user[key] = f.get(key).value
}
});
I keep a copy of the original object and then do this:
get isDirty(): boolean {
return JSON.stringify(this.originalProduct) !== JSON.stringify(this.currentProduct);
}
I stringify the copy of the original product (before edits) and the current product and compare them. I assume if they are not equal that something changed.
There are some caveats to this approach, especially if your object structure is complex as there may be cases that stringify does not create the strings exactly the same. But I have not run into this case.

format json data in javascript like a pivot table

I have the the following data being returned by my api.
[{"category":"Amazon","month":"Feb","total":9.75},
{"category":"Amazon","month":"Mar","total":169.44},
{"category":"Amazon","month":"Apr","total":10.69},
{"category":"Amazon","month":"May","total":867.0600000000001},
{"category":"Amazon","month":"Jun","total":394.43999999999994},
{"category":"Amazon","month":"Jul","total":787.2400000000001},
{"category":"Amazon","month":"Aug","total":1112.4400000000003},
{"category":"Amazon","month":"Sep","total":232.86999999999998},
{"category":"Amazon","month":"Oct","total":222.26999999999998},
{"category":"Amazon","month":"Nov","total":306.09999999999997},
{"category":"Amazon","month":"Dec","total":1096.2599999999998}]
I want to format it so that the months are all grouped under each category like this:
[{"category":"Amazon","month":{"Jan":9.75,"Feb":9.75,"Mar":9.75,"Apr":9.75,etc...}]
How can I do this with javascript?
What I'm ultimately trying to do is to display some pivoted data in a table. I'm not sure what the best design is to accomplish this.
Right now, I'm just setting up a table dynamically and adding in the data corresponding to each row. Are there better design patterns for doing this?
You can reduce the array of objects to an object using the categories as keys, and adding the months, and then map it back to an array again
var arr = [{"category":"Amazon","month":"Feb","total":9.75},
{"category":"Amazon","month":"Mar","total":169.44},
{"category":"Amazon","month":"Apr","total":10.69},
{"category":"Amazon","month":"May","total":867.0600000000001},
{"category":"Amazon","month":"Jun","total":394.43999999999994},
{"category":"Amazon","month":"Jul","total":787.2400000000001},
{"category":"Amazon","month":"Aug","total":1112.4400000000003},
{"category":"Amazon","month":"Sep","total":232.86999999999998},
{"category":"Amazon","month":"Oct","total":222.26999999999998},
{"category":"Amazon","month":"Nov","total":306.09999999999997},
{"category":"Amazon","month":"Dec","total":1096.2599999999998}];
var o = arr.reduce( (a,b) => {
a[b.category] = a[b.category] || [];
a[b.category].push({[b.month]:b.total});
return a;
}, {});
var a = Object.keys(o).map(function(k) {
return {category : k, month : Object.assign.apply({},o[k])};
});
console.log(a);
I would take the following approach:
Write down on a piece of paper how to solve the problem (the "algorithm").
Flesh out this algorithm with more details. Sometimes this is called "pseudo-code".
Convert the pseudo-code into JavaScript.
For instance, your algorithm might look like this:
Create a new thing to hold the results.
Loop through the elements in the input.
For each element in the input, update the results thing.
Return the result.
Sometimes it helps to read out the algorithm aloud to yourself. Or animate the algorithm on a blackboard. Or talk through the algorithm with someone nearby.
The pseudo-code might be:
Create a new array containing a new object to hold the results, with a category property set to "Amazon", and a months property set to an empty object.
Loop through the elements in the input array.
For each element, add a new property to the months property of the results object, whose key is the value of the month property from the element, and whose value is the value of the total property from the element.
Return the result.
If you have specific questions about any of those steps, you can research it further, or ask, such as:
How do I create a new array, with an object inside?
How do I loop through the elements of an array?
How do I retrieve a property from an object?
How do I add a new key/value pair to an object?
How do I return the result?
If you are unfamiliar with any of the terms used above--such as array, object, property, key, value, or element--research them and make sure you know what they mean. Knowing and using correct terminology is the first step to successful programming!
When converting your algorithm into JS, write it step by step, and test it at each phase. For instance, start with a version which doesn't loop over the input at all, and make sure it produces a correct output of [{category: "Amazon", month: {}}]. Walk though your code in the debugger at this and each following step--if you don't know how to use the debugger, learning that should be your first priority! If you want to check a little bit of syntax, to make sure it does what you think, just try it out by typing it into the console. If you don't know what the console is, learning that should be another top priority.
All the above assumes that you've got a single Amazon category. If you are going to have multiple categories, and want multiple objects (one for each) in your output array, then start over from the top and write the algorithm and pseudo-code which can handle that.

Lucene-like searching through JSON objects in JavaScript

I have a pretty big array of JSON objects (its a music library with properties like artist, album etc, feeding a jqgrid with loadonce=true) and I want to implement lucene-like (google-like) query through whole set - but locally, i.e. in the browser, without communication with web server. Are there any javascript frameworks that will help me?
Go through your records, to create a one time index by combining all search
able fields in a single string field called index.
Store these indexed records in an Array.
Partition the Array on index .. like all a's in one array and so on.
Use the javascript function indexOf() against the index to match the query entered by the user and find records from the partitioned Array.
That was the easy part but, it will support all simple queries in a very efficient manner because the index does not have to be re-created for every query and indexOf operation is very efficient. I have used it for searching up to 2000 records. I used a pre-sorted Array. Actually, that's how Gmail and yahoo mail work. They store your contacts on browser in a pre-sorted array with an index that allows you to see the contact names as you type.
This also gives you a base to build on. Now you can write an advanced query parsing logic on top of it. For example, to support a few simple conditional keywords like - AND OR NOT, will take about 20-30 lines of custom JavaScript code. Or you can find a JS library that will do the parsing for you the way Lucene does.
For a reference implementation of above logic, take a look at how ZmContactList.js sorts and searches the contacts for autocomplete.
You might want to check FullProof, it does exactly that:
https://github.com/reyesr/fullproof
Have you tried CouchDB?
Edit:
How about something along these lines (also see http://jsfiddle.net/7tV3A/1/):
var filtered_collection = [];
var query = 'foo';
$.each(collection, function(i,e){
$.each(e, function(ii, el){
if (el == query) {
filtered_collection.push(e);
}
});
});
The (el == query) part of course could/should be modified to allow more flexible search patterns than exact match.

Query using multiple conditions

I recently discovered (sadly) that WebSQL is no longer being supported for HTML5 and that IndexedDB will be replacing it instead.
I'm wondering if there is any way to query or search through the entries of an IndexedDB in a similar way to how I can use SQL to search for an entry satisfying multiple conditions.
I've seen that I can search through IndexedDB using one condition with the KeyRange. However, I can't seem to find any way to search two or more columns of data without grabbing all the data from the database and doing it with for loops.
I know this is a new feature that's barely implemented in the browsers, but I have a project that I'm starting and I'm researching the different ways I could do it.
Thank you!
Check out this answer to the same question. It is more detailed than the answer I give here. The keypath parameter to store.createIndex and IDBKeyRange methods can be an array. So, crude example:
// In onupgradeneeded
var store = db.createObjectStore('mystore');
store.createIndex('myindex', ['prop1','prop2'], {unique:false});
// In your query section
var transaction = db.transaction('mystore','readonly');
var store = transaction.objectStore('mystore');
var index = store.index('myindex');
// Select only those records where prop1=value1 and prop2=value2
var request = index.openCursor(IDBKeyRange.only([value1, value2]));
// Select the first matching record
var request = index.get(IDBKeyRange.only([value1, value2]));
Let's say your SQL Query is something like:
SELECT * FROM TableName WHERE Column1 = 'value1' AND Column2 = 'value2'
Equivalent Query in JsStore library:
var Connection = new JsStore.Instance("YourDbName");
Connection.select({
From: "YourTableName"
Where: {
Column1: 'value1',
Column2: 'value2'
},
OnSuccess:function (results){
console.log(results);
},
OnError:function (error) {
console.log(error);
}
});
Now, if you are wondering what JsStore is, let me tell you it is a library to query IndexedDB in a simplified manner. Click here to learn more about JsStore
I mention some suggestions for querying relationships in my answer to this question, which may be of interest:
Conceptual problems with IndexedDB (relationships etc.)
As to querying multiple fields at once, it doesn't look like there's a native way to do that in IndexedDB (I could be wrong; I'm still new to it), but you could certainly create a helper function that used a separate cursor for each field, and iterated over them to see which records met all the criteria.
Yes, opening continuous key range on an index is pretty much that is in indexedDB. Testing for multiple condition is not possible in IndexedDB. It must be done on cursor loop.
If you find the solution, please let me know.
BTW, i think looping cursor could be very fast and require less memory than possible with Sqlite.
I'm a couple of years late, but I'd just like to point out that Josh's answer works on the presumption that all of the "columns" in the condition are part of the index's keyPath.
If any of said "columns" exist outside the the index's keyPath, you will have to test the conditions involving them on each entry which the cursor created in the example iterates over. So if you're dealing with such queries, or your index isn't unique, be prepared to write some iteration code!
In any case, I suggest you check out BakedGoods if you can represent your query as a boolean expression.
For these types of operations, it will always open a cursor on the focal objectStore unless you're performing a strict equality query (x ===? y, given x is an objectStore or index key), but it will save you the trouble writing your own cursor iteration code:
bakedGoods.getAll({
filter: "keyObj > 5 && valueObj.someProperty !== 'someValue'",
storageTypes: ["indexedDB"],
complete: function(byStorageTypeResultDataObj, byStorageTypeErrorObj){}
});
Just for the sake of complete transparency, BakedGoods is maintained by moi.

jQuery "Autocomplete" plugin is messing up the order of my data

I'm using Jorn Zaefferer's Autocomplete plugin on a couple of different pages. In both instances, the order of displayed strings is a little bit messed up.
Example 1: array of strings: basically they are in alphabetical order except for General Knowledge which has been pushed to the top:
General Knowledge,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
General Knowledge,Geography,Art and Design,Business Studies,Citizenship,Design and Technology,English,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Note that Geography has been pushed to be the second item, after General Knowledge. The rest are all fine.
Example 2: array of strings: as above but with Cross-curricular instead of General Knowledge.
Cross-curricular,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
Cross-curricular,Citizenship,Art and Design,Business Studies,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Here, Citizenship has been pushed to the number 2 position.
I've experimented a little, and it seems like there's a bug saying "put things that start with the same letter as the first item after the first item and leave the rest alone". Kind of mystifying. I've tried a bit of debugging by triggering alerts inside the autocomplete plugin code but everywhere i can see, it's using the correct order. it seems to be just when its rendered out that it goes wrong.
Any ideas anyone?
max
EDIT - reply to Clint
Thanks for pointing me at the relevant bit of code btw. To make diagnosis simpler i changed the array of values to ["carrot", "apple", "cherry"], which autocomplete re-orders to ["carrot", "cherry", "apple"].
Here's the array that it generates for stMatchSets:
stMatchSets = ({'':[#1={value:"carrot", data:["carrot"], result:"carrot"}, #3={value:"apple", data:["apple"], result:"apple"}, #2={value:"cherry", data:["cherry"], result:"cherry"}], c:[#1#, #2#], a:[#3#]})
So, it's collecting the first letters together into a map, which makes sense as a first-pass matching strategy. What i'd like it to do though, is to use the given array of values, rather than the map, when it comes to populating the displayed list. I can't quite get my head around what's going on with the cache inside the guts of the code (i'm not very experienced with javascript).
SOLVED - i fixed this by hacking the javascript in the plugin.
On line 549 (or 565) we return a variable csub which is an object holding the matching data. Before it's returned, I reorder this so that the order matches the original array of value we were given, ie that we used to build the index in the first place, which i had put into another variable:
csub = csub.sort(function(a,b){ return originalData.indexOf(a.value) > originalData.indexOf(b.value); })
hacky but it works. Personally i think that this behaviour (possibly coded more cleanly) should be the default behaviour of the plugin: ie, the order of results should match the original passed array of possible values. That way the user can sort their array alphabetically if they want (which is trivial) to get the results in alphabetical order, or they can preserve their own 'custom' order.
What I did instead of your solution was to add
if (!q && data[q]){return data[q];}
just above
var csub = [];
found in line ~535.
What this does, if I understood correctly, is to fetch the cached data for when the input is empty, specified in line ~472: stMatchSets[""] = []. Assuming that the cached data for when the input is empty are the first data you provided to begin with, then its all good.
I'm not sure about this autocomplete plugin in particular, but are you sure it's not just trying to give you the best match possible? My autocomplete plugin does some heuristics and does reordering of that nature.
Which brings me to my other answer: there are a million jQuery autocomplete plugins out there. If this one doesn't satisfy you, I'm sure there is another that will.
edit:
In fact, I'm completely certain that's what it's doing. Take a look around line 474:
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
/* some code */
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
and so on. So, it's a feature.

Categories