See edit too
I'm working in JavaScript but readable psuedocode of any kind may be able to answer my question.
I'm going to struggle describing this so please feel free to comment clarifications - I will answer them and refine my post accordingly.
Essentially, I have an array that acts as a queue, items are added, and when they are processed they need to be removed and more will eventually be added. What is the fastest way to get the first item in an array when I don't care about the index? I just want to iterate on a first-added basis without having to shift all entries in the array down each time. Also worth mentioning I am not looping through the array, I have a master loop for my app that checks if the array has items on each loop, and if it does, it will grab that data then remove it from the array. Currently to do this quickly I use pop, but now recognize I need to get the oldest item in the queue first each time, not the newest.
For more clarification if needed:
In my app I have blocks of raw data that first need to be ran through a function to be ready to be used by other parts of my app. Each block has a unique ID that I pass to the function in order for it to be parsed. For optimization purposes I only parse the blocks of data as it is needed.
In order to do this, my current system is when I realize I need a block to be parsed, I push its unique ID into an array, then a continuous loop in my app checks said array constantly, seeing if it has items in it. If it does, it pops the last item of the array and passes the unique id into the parsing function.
For performance reasons, on each iteration of the loop, only one block of data can be parsed. The issue arises when multiple blocks of data are in queue array already, and I add more items to the array before the loop can finish passing the already existing ID's in the array to the function. Basically, new ID's that are needed to be parsed are added to the end of the array before my loop can clear them out.
Now, this isn't all too bad because new data is needed somewhat sparsely, but when it is, lots of ID's are added at once, and this is an attribute of the app I can't really change.
Since I'm using pop, the most recently added ID is obviously always parsed first, but I chose this method as I believed it to be the fastest way to iterate a queue like this. However, I've come to realize I would rather parse the oldest items in the list first.
In essence, I'm looking for a way to loop through an array oldest to newest without having to re-organize the array each time. The index of the array is not important, I just need first-added, first-parsed behavior.
For example, I know I could always just pass the 0th item in the array to my function then shift the rest of the entries down, however, I believe having to shift down the rest of the items in the array is too costly to performance and not really worth it. If I'm just dumb and that should have no real-world cost please let me know, but still it seems like a band-aid fix. I'm certain there is a better solution out there.
I'm open to other data structures too as the array only holds strings.
Thank you
EDIT: While doing more googling I'm having a face palm moment and realized the problem I'm describing is a stack vs a queue. But now my question moves to what is the fastest implementation of a queue when the index isn't really of value to me?
The following is the FIFO queue implementation using singly linked list in javascript.
For more information of linked list -> https://www.geeksforgeeks.org/linked-list-set-1-introduction/
// queue implementation with linked list
var ListNode = function(val,next = null){
this.val = val
this.next = next
};
var Queue = function(){
let head = null;
let tail = null;
this.show = function(){
let curr = head;
let q = [];
while(curr){
q.push(curr.val);
curr = curr.next;
}
return q.join(' -> ');
}
this.enqueue = function(item){
let node = new ListNode(item);
if(!head) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
}
this.dequeue = function(){
if(!head) return null;
else {
let first = head;
head = head.next;
first.next = null;
return first;
}
}
}
var myQueue = new Queue();
myQueue.enqueue(1); // head -> 1
console.log(myQueue.show())
myQueue.enqueue(2); // head -> 1 -> 2
console.log(myQueue.show())
myQueue.enqueue(3); // head -> 1 -> 2 -> 3
console.log(myQueue.show())
myQueue.dequeue(); // head -> 2 -> 3
console.log(myQueue.show())
I am trying to sort sets of associated key value pairs. They look like this:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
But organized into labeled subsets of preferably a string or perhaps an index if necessary.
The data-set is a vote-per-use table of most used english words being parsed into pages.
I will be appending them as text to other html elements due to the constraints my use case, makes it a bit tricky, however, for an example I could work with a simple console.log of the page value followed by the console.log of every word value stored within that page. I need the order preserved. so probably indexed. I will also need to be able to sort each page by the votes value, but I think I can figure the rest out for that.
I have found tutorials on how to search through key-value pairs, but I cannot find how to do all of the following with one solution:
A: access the value of word
B: maintain the order of the data-set, allowing me to append them to the matching html element
C: allows me the opportunity to change which set of elements I am appending to when i have finished looping through a single member of the parent index (the one recording the page)
I imagine it is some combination of for/of and for/in, but I'm getting a headache. Please help?
addl info:
function would run at app startup or when the dataset being examined is changed.
function would take a large dataset filled with around 200 page number values, each with 60+ sets of data like the one listed above, the contents of a single page index for example:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abandoned","votes":1289,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abc","votes":5449,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aberdeen","votes":641,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abilities","votes":2210,"userMade":"FALSE","limiter":"FALSE"},
{"word":"ability","votes":7838,"userMade":"FALSE","limiter":"FALSE"},
{"word":"able","votes":8649,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aboriginal","votes":1837,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abortion","votes":3232,"userMade":"FALSE","limiter":"FALSE"},
{"word":"about","votes":9295,"userMade":"FALSE","limiter":"FALSE"},
{"word":"above","votes":8818,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abraham","votes":867,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abroad","votes":4969,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abs","votes":2415,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absence","votes":4934,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absent","votes":2937,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolute","votes":5251,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolutely","votes":5936,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absorption","votes":285,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstract","votes":7946,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstracts","votes":1907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abuse","votes":7238,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academic","votes":7917,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academics","votes":1706,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academy","votes":6755,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acc","votes":6469,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accent","votes":1020,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accept","votes":7547,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptable","votes":4907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptance","votes":7273,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepted","votes":7684,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepting","votes":1789,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepts","votes":1535,"userMade":"FALSE","limiter":"FALSE"},
{"word":"access","votes":9031,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessed","votes":2932,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessibility","votes":5702,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessible","votes":5662,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessing","votes":2096,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessories","votes":8875,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessory","votes":5661,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accident","votes":5664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accidents","votes":2991,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodate","votes":1807,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodation","votes":8059,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodations","votes":3885,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanied","votes":2532,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanying","votes":664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplish","votes":1070,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplished","votes":2419,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordance","votes":6434,"userMade":"FALSE","limiter":"FALSE"},
{"word":"according","votes":8282,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordingly","votes":3003,"userMade":"FALSE","limiter":"FALSE"},
{"word":"account","votes":8996,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accountability","votes":3029,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounting","votes":7459,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounts","votes":7507,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accreditation","votes":1605,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accredited","votes":3027,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accuracy","votes":6779,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurate","votes":6427,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurately","votes":1493,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accused","votes":2853,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acdbentity","votes":1389,"userMade":"FALSE","limiter":"FALSE"},
and the output would ultimately append the value paired with each word to a specific button through iteration, but also sorted by the page value.
each page is a set of buttons in a 3d object that looks like this:
the text is appended to each button which in turn is a 3d object embeded in an html object using aframe. I can make the appending code.
You can use Object.entries() to get the key value pairs of an object.
var words = [
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"}
];
words.forEach((wordEntry) => {
var keyValuePairs = Object.entries(wordEntry);
keyValuePairs.forEach((kv) => {
console.log(`key: ${kv[0]} value: ${kv[1]}`);
});
});
my latest attempt looks like this:
for (let p=1; p<129; p++){
for (let b=1; b<68; b++){
let pTpl = (p).toLocaleString(undefined, {minimumIntegerDigits: 3});
let bDbl = (b).toLocaleString(undefined, {minimumIntegerDigits: 2});
var `#fCont${pTpl}${bDbl}` = document.createElement('a-text');
`fCont${pTpl}${bDbl}`.setAttribute('value', 'engWordLib[p,b,0]');
`fCont${pTpl}${bDbl}`.setAttribute('votes', 'engWordLib[p,b,1]');
`fCont${pTpl}${bDbl}`.setAttribute('userMade', 'engWordLib[p,b,2]');
`fCont${pTpl}${bDbl}`.setAttribute('limiter', 'engWordLib[p,b,3]');
`fCont${pTpl}${bDbl}`.setAttribute('visible', 'false');
`fBtn${bDbl}`.appendChild(`#fCont${pTpl}${bDbl}`)
}
}
please note that I havent checked this for errors. I still think this code is to WET and I would prefer the key names for the properties be preserved in the datastructure rather than tacked on when it's appended to the page. I guess I could add a dimension to the array.... seems kind of messy when an object property value has the key value pairs right in it. cant get the iteration of objects in an array down though.... Will continue to persue a cleaner method.
I have been working through a nodeschool tutorial: learnyounode, which can be found here. I was working on challenge five (FILTERED LS).
The challenge was this:
Create a program that prints a list of files in a given directory, filtered by the extension of the files. You will be provided a directory name as the first argument to your program (e.g. '/path/to/dir/') and a file extension to filter by as the second argument.
This is my code so far:
var fs = require('fs');
var path = require('path');
extname = '.' + path.extname(process.argv[3]);
console.log(extname);
fs.readdir(process.argv[2].toString(), function(err, list) {
if (err) {
throw err;
}
list.filter(extname);
console.log(list);
});
How do I effectively filter out all files that are given as a console argument? Does it have something to do with path.extname? If so, how? I have tried using .filter(), but that does not seem to work. Would someone also be able to explain to me how .filter() works as well as its arguments as I have found documentation to be a bit confusing. Finally, is there a better way to output the elements of an array on separate lines than console.log()?
Thanks
It looks like your usage of .filter() - instead of providing the extension name as the argument of the function, you need to supply a callback that will be called on each element of the list, and only return the values that pass a specific test (in this case the file extension is present in the string).
For example
var filelist = ['woohoo.txt', 'aha.pdf', 'wahoo.txt'];
var extension = '.txt';
var x = filelist.filter(function(file){
return file.indexOf(extension) !== -1;
});
console.log(x); // expected output: ['woohoo.txt', 'wahoo.txt']
Javascript uses closures, and so the variable "extension" is accessible in the function scope, since it is available in the parent
You are using .filter incorrectly. This method is receiving a function argument which is being applied to each of the array elements and decides if this elements should remain in the new list. What you did was to supply this function a string, but how should it use this string to filter the array elements? Should it take the elements that has this string as a prefix? Should it take the elements that doesn't contain this string?
You should determine the way that your program would choose which string to keep and which to discard.
In your case, you are looking to filter by an extension (or postfix). The function you can pass for this purpose might be, for example:
list.filter(file => file.endsWith(extname));
This would pass file by file and select only those that ends with the given extension, as you wanted.
the problem with andrewkodesgood's answer is that the given extension doesn't have to be placed at the end of the file name, but also in the middle or even the beginning.
Just one other possible way.
let files = [
'/Users/dave/Movies/2021-09-16 08-29-25.mp4',
'/Users/dave/Downloads/video.mp4',
'/System/Library/Movies/Regular.mov',
'/System/Library/Movies/Regular.ttf',
'/System/Library/Movies/Regular.txt',
'/System/Library/Movies/Regular.pdf'
];
let filtered = files.filter(file => ['mp4', 'mov'].includes(file.split('.').pop()));
console.log(filtered);
Outputs
/*
["/Users/dave/Movies/2021-09-16 08-29-25.mp4", "/Users/dave/Downloads/video.mp4", "/System/Library/Movies/Regular.mov"]
*/
On return of a JSON file I can't seem to be able to detect how many results are returned. The problem seems to be with the JSON file returning a diffrent number of items each time. At times it will return 1 item, then at other it will return more than 1. You see, I'm trying to get the very first result from the JSON file so I can display it. Now, If change the code everytime I know the number that will be returned, the following two bits of code work.. Artists.id; and Artists.id[0];, but I can't seem to make them work together, at the momment..
If 1 result is returned, Artists.id; will successfully bring back the artist ID;
If more than 1 result is returned Artists.id; will return "undefined".
So I need to change it to Artists.id[0]; if the JSON file returns more than 1 item. However when I change it to this, if the JSON conatins 1 item, it will return "undefined".
It seems I need some code to tell me if the returned array has 1 or more items. I've tried arr.length but that doesn't seem to be working (perhaps i miss-coded it). I also tried if(arr===undefined) and that failed to work too. The code below is what I have come up with, using the artistzero, but it is not working. Anyone has any advice? or a reason why the code below would not work?
Current Code:
$.ajax(
{
type: "GET",
url: id_url,
dataType: "jsonp",
success: function (responseData, textStatus, XMLHttpRequest)
{
if (responseData.Artists.Artist)
{
var Artists = responseData.Artists.Artist;
var artistzero = Artists.length;
if (artistzero >= 2)
{
// if more than one result is returned
var artisttype = Artists.id[0];
}
if (artistzero <= 1)
{
// if one result is returned
var artisttype = Artists.id;
}
}
else
{
$('body').append('No results');
}
}
});
Sample JSON with 1 result:
{"Artists":{"total":"1","count":"1","start":"1","errorCount":"0","Artist":{"id":"33291476","flags":"123010","catzillaID":"0","website":"","name":"Jamie T","rating":"-1","ItemInfo":{"Relevancy":{"index":"1316"}},"hotzillaID":"1809709440","url":"http://web.com/jamie-t/","trackCount":"96"}}}
Sample JSON with more than one result:
{"Artists":{"total":"1087","count":"3","start":"1","errorCount":"0","Artist":[{"id":"256212","flags":"123523","catzillaID":"1927205428","website":"http://www.bobmarley.com/","name":"Bob Marley","rating":"-1","ItemInfo":{"Relevancy":{"index":"718"}},"hotzillaID":"1802045595","url":"http://web.com/bob-marley/","trackCount":"12706"},{"id":"312874","flags":"124611","catzillaID":"1927580000","website":"http://www.bobdylan.com/","name":"Bob Dylan","rating":"-1","ItemInfo":{"Relevancy":{"index":"694"}},"hotzillaID":"1800021697","url":"http://web.com/bob-dylan/","trackCount":"4987"},{"id":"268472","flags":"41603","catzillaID":"1927193413","website":"","name":"Bob Wills","rating":"-1","ItemInfo":{"Relevancy":{"index":"644"}},"hotzillaID":"1800264434","url":"http://web.com/bob-wills/","trackCount":"2364"}]}}
You need to access the first artist before grabbing the id (since it's an array) like this:
var artisttype = Artists[0].id;
It would be better if you could change the JSON to always return an Array, even with one result...unfortunately some platforms don't do this, for reasons beyond my comprehension.
for(var propertyname in responseData){
//will loop through the different elements in your json array
alert(responseData[propertyName]); //will output the valueof each element
}
You're right that this is problematic, and to be honest it sounds like the "other end" that's sending you the JSON is being inconsistent.
The problem is that when there are multiple items they're sending you an array for the id property, and when there's a single item they're just sending you a simple value (e.g. an integer). Ideally, when there is a single item you should be sent a single-item array - this would let you use the same array-based parsing code every time.
If you can't convince them to change what they're sending you, though, then the best bet is simply to do what you're currently doing; see if Artists.id is defined, use it if so, else fall back to accessing id as an array.
However, if more than 1 result is returned Artists.id; will return "undefined". So I need to change it to this: Artists.id[0];
this cannot be Artists.id should be "object" not undefined if Artists.id[0] exists. Maybe it is as stated Artists[0].id ? and if so you could test typeof(Artists) == typeof([])