how to optimize this traditional "for" loop for this case? - javascript

I'm playing with an Angular app, I have a method in a service that raises an HTTP get request to JSONplaceholder, and the response is an object array with 100 posts. I was wondering how can I render only 10 out of those 100 posts, and only could think about creating an auxiliary variable and do the following:
posts:any;
modified:any[] = [];
ngOnInit(): void {
this.dataService.getPosts().subscribe( res =>
{
this.posts = res;
for (let i = 0; i < this.posts.length; i++) {
i < 10 ? this.modified.push(this.posts[i]) : void(0);
}
}
)
}
This works, but I have to iterate the modified variable in my template, and I'm pretty sure there are better ways to improve this, with a better approach. How can this little code be a little better?
Thanks

Use array.slice - the function takes two parameters, 'start' and 'end'.
'end' signifies the index after the last item that you want (it is not inclusive of the 'end' index), and is optional. If 'end' is not supplied, you will get all elements starting at end and continuing to the end of the array.
So, in your case,
modified = posts.slice(0, 10);

just concerning the for loop you can do
for ( let i=0, len=this.posts.length; i<len; i++ ){
// code
}
this way you will only run this.posts.length once (this is just in case ths.posts has lots of data)

To handle arrays you can always check the JavaScript Array docs: https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array
In this case you could use the slice method:
this.modified = res.slice(0,10);

Related

get string from an array?

trying to loop on string array but it throws error foreach is not a function what is correct way to implement using typescript ?
main.ts
content = ["renewel","payments"]
if i do for loop
for (let i = 0, len = content.length; i < len; i++) {
console.log(content[i]);
}
it prints all indexs [r e n e etc
if do foreach
content.forEach(function(content){
console.log(content);
})
it throws error content.forEach is not a function
Your code works just fine; it's very likely you've mutated content's type in some way at some point in your code. Ensure any functions you may be passing it (content) to aren't mutating the original array.
You might also consider using newer syntax, like:
content.forEach(item => {
console.log(item);
});
or even
content.forEach(item=> console.log(item));
Two small things, by the way; there's no need to cache length in a for loop (JS engine does that for you), and I don't know if it matters or not... but you've misspelled 'renewal' ;)

finding if all items in array are set to expected value in javascript? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am fairly new to javascript and I am learnig by doing a project.
I have a situtation in which I collect statuses of various tasks to an array.
var statuses = ["deployed", "deployed", "pending", "staged"];
now I want to call clearInterval(interval) when all the items in the array are deployed
var statuses = ["deployed", "deployed", "pending", "staged"];
if(statuses.every(x=>x === "deployed")){
//clearInterval(interval);
}
console.log(statuses.every(x=>x === "deployed"))
You can use every to check if all elements in array are deployed. The above code is based solely on your description I want to call clearInterval(interval) when all the items in the array are deployed
Use the every method:
if (statuses.every(status => status === "deployed")) {
clearInterval(interval);
}
Iterate over 'statuses', checking each current value for NOT "deployed". The first time that condition is met, you know you do not need to perform the 'clearInterval' logic. This means that if the condition is never met, you can proceed with that logic.
So here is what I think you should do, and it works pretty well. Ill break everything down so it makes sense.
/// I just dont like using strings when ints will suffice, so im using 0,1,2 instead of your defined strings.
var valueRef = { 0: "Deployed", 1: "Pending", 2: "Staged" };
/// Info contains your sample data.
var info = [0,0,1,2]
/// This will be needed to clear the repeating fn call
var timeoutKey;
function checkIfAllDeployed(){
/// Get the size of your info array
var len = info.length;
for (index in info){
/// Loop through all items in the array to check to see if they are 0 (deployed)
if (info[index] == 0){
/// it is 0, subtract 1.
len --;
}
}
/// since you have the length (this sample is 4), when the function finally runs and they are all deployed, then len will now be 0 here.
if (len <= 0){
/// Turn off the timeout.
clearTimeout(timeoutKey);
}
/// I use bind so that what the scope is the same as the parent, so it has access to timeoutKey
}.bind(this);
/// Sets your timeout. This is where you kick it all off at. It will run at an interval of whatever you want. 1000 == 1 second. So 500 = 0.5 seconds.
timeoutKey = setInterval(checkIfAllDeployed, 500)
Now, that covers loops, but since you are doing ES6, there are some cool tricks such as the every function for arrays. It takes a function to compare.
var timeoutKey
function checkIfAllDeployed(){
if (info.every(function(item){ return item == 0}){
clearTimeout(timeoutKey)
}
}
setInterval(checkIfAllDeployed, 500);
Or if you want to use shorthand:
var timeoutKey
function checkIfAllDeployed(){
/// Now in my example, i use 0, but you can use the string "deployed" here.
if (info.every(x => x == 0){
clearTimeout(timeoutKey)
}
}
setInterval(checkIfAllDeployed, 500);
Now the reason I use INTS etc is that it takes up less space. There are far less strings. Imagine a HUGE array of strings. Not too good, but with a map you can easily rereference.
If you decide you every need data for a given row you can just say:
valueRef[info[index]]
and it will give you the String you are looking for. This is kinda like an enum, Which you could also used if you wanted. Since you have a static set of states, you could just create an enum and it would work similar to the map example i gave you.
Ciasto!
From my understanding, you are just trying to iterate through the statuses array and verify that each element of that array only contains the strings "deployed". This code below is a simple implementation of that and I've inserted a few console log statements to help show the logic of stepping through the process.
function isDeployed(array) {
for (var i = 0; i < statuses.length; i++) {
if (statuses[i] !== 'deployed') {
return false;
}
}
return true;
}
var statuses = ["deployed", "deployed", "pending", "staged"];
// var statuses = ["deployed", "deployed", "deployed", "deployed"];
var result = isDeployed(statuses);
console.log(result);
if (result) {
console.log('Add more code to deal with your next steps');
}
Let me know if you need further clarification or if this isn't quite what you were asking!

Effective algorithm to find the latest updated json

I receive some information by a request in javascript.
I have a json variable: var response for example.
Then each of them has an update date element:
response[0].updateDate
is the updateDate of the first element of my response.
How to find the element with the last updateDate?
I can do something like:
var actualElement = 0
for(var i = 0; i < response.length; i++){
if(response[actualElement].updateDate < response[i].updateDate){
actualElement = i;
}
}
Are you a more effective solution?
Sorting is not the fastest solution (though it's the prettiest), because it needs to iterate twice. If you just want the last, you can also use something like:
response.reduce((max, c) => max.updateDate > c.updateDate ? max : c, response[0]);
Thtat's if performance is a must for you.
PS. Or, without arrow functions:
response.reduce(function(max, c) {
return max.updateDate > c.updateDate ? max : c;
}, response[0]);
Just sort and get the first one
response.sort((a, b) => b.updateDate - a.updateDate)
response[0]
Since it is the strategy used by the UnderscoreJS library (widely used), I'd say it's the fastest.
It'd be even better if your server could order the array for you so you could know in advance the first element is the one you're looking for.

Convert for loop to a while loop in JavaScript

I've been trying to convert the following JS code that uses a for loop to a while loop and/or do-while loop.
var unique = function(array)
{
var newArray = []
array.sort()
for(var x in array) if(array[x] != array[x-1]) newArray.push(array[x])
return newArray
}
The code is suppose to return only distinct names from an array of names that repeat. I've been trying to convert the for loop but so far I've been running into problems using this:
do
{
newArray.push(array[x])
}
while(array[x] != array[x-1])
return newArray;
Can anyone help me? Thanks!
Is it guaranteed that your names are only going to be duplicated in sequence i.e. is it true that if a name does have a duplicate it will be directly after it? If not, then checking the elements that are directly next to each will not find all the duplicates. You'll have to do a nested for loop or some other n^2 algorithm.
var duplicated = false;
for (int x = 0; x < array.length; x++)
{
for (int y = 0; y < array.length; y++)
{
if (array[x] == array[y])
{
duplicated = true;
}
}
if (!duplicated)
{
array.push(array[x]);
}
duplicated = false;
}
return newArray;
please note, this implementation is very poor but it gets the point across.
You're very close. The following preserves the original sequence:
function getUnique(array) {
var newArray = array.slice(); // copy original
var i = newArray.length - 1;
do {
if (newArray[i] == newArray[--i]) {
newArray.splice(i, 1);
}
} while(i)
return newArray;
}
Note that the above assumes a sorted, contiguous array (no missing members). If you can't be sure of that, sort newArray before the do..while loop and maybe compact it to make it contiguous.
A while loop doesn't make sense for your use case. A while loop is good when you want to loop as long as some condition is met and then stop the first time it fails. But a for loop is good when you want to loop through a certain number of items (for instance all of them).
So stick with a for loop. Also a few notes on while loops for whenever you do use them:
A for loop automatically updates the loop index which in your case is x. A while loop doesn't. So, to replicate your for loop, you would need to manually increment x.
Also, you test at the top of the for loop. To mirror that behavior you would want a while instead of a do- while (while tests before executing each loop, do-while tests after).
But if you used a while loop, you'd exit the loop the first time array[x] != array[x-1] failed. And it sounds like you don't want that. You want to push all values that meet that test.

get sub array of array javascript

I have a array in javascript and I want a sub array of the array with element which are at position n*3, n=0,1,2.. for example if:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12]
var subArr = [1,4,7,10]
Edit : any soln without looping.
Here's an example of a fancy way :
var brr = [1,2,3,4,5,6,7,8,9,10,11,12].filter(function(_,i){ return !(i%3) })
But a simple loop would have been as good (and would have been compatible with IE8). note that filter, even if it's not visible, does loop over the array. You can't avoid a loop (at least for an arbitrary sized array) even if you may disguise it.
Here's how you would do it with a standard loop :
var brr = [];
for (var i=0; i<arr.length; i+=3) brr.push(arr[i])
Performance is rarely a concern on such operations client side but you might find important to know that the for loop is much faster here : http://jsperf.com/looporfilter
In order to operate on a set of data of size n, m times, where m > 1, how would you avoid iteration? Really, there is no way unless you use a set of O(1) operations like this:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
subarr.push(arr[0]);
subarr.push(arr[3]);
subarr.push(arr[6]);
subarr.push(arr[9]);
Here is a structural recursion (which can be represented by a loop, and does technically loop).
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
(function recur(n){
if( n >= arr.length ) return;
subarr.push(arr[n]);
recur(n+3);
})(0);
To note: a straight for loop will always be faster. In an expansion of #dystroy's jsperf, this recursion ran slower than the for loop, but faster than the filter. http://jsperf.com/looporfilter/2
just for kicks, i searched for a way to actually do it without a loop like the OP wanted.
without using a loop, it's tough.
the closest i could manage gets the right numbers, but converts them to Strings instead of numbers.
var r=[1,2,3,4,5,6,7,8,9,10,11,12,13,14];
alert( "".replace.call(r+",-0,-0,-0", /(\d+),\d+,?(\d+,|$)/g, "$1,")
.replace(/(,?\-0){1,4}$/g,"")
.split(",") );
//shows: 1,4,7,10,13
if you need strong numbers, it's easy, but i am not sure if adding .map(Number) after .split(",") would constitute a loop in your book, but this is the only version that actually finds the desired results without a loop.
this also only works on positive integers as coded.
again, more for fun than something i would recommend using; don't be afraid of loops...
Here's a solution with no loop:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
// pickInterval is a function that automatically picks every "n"
// elements from an array, starting with the first element
var subArr = pickInterval( arr, 3 );
// now subArr is [1,4,7,10]
Simple, isn't it? And not a loop in sight.
Ah, but you ask, "What's the catch? You haven't implemented that pickInterval() function, have you? I bet there's a loop in it."
And you're right. Even if we write our pickInterval() function using some other function that doesn't look like a loop, that function will have a loop in it. And if that one just calls yet another function, eventually you will find a loop.
It may be turtles all the way down, but there's a loop underneath them all.
So, to implement pickInterval(), we could use either approach from #dystroy's answer. We can put the loop right inside the function:
function pickInterval( array, interval ) {
var result = [];
for( var i = 0, n = array.length; i < n; i += 3 )
result.push( array[i] );
return result;
}
Or we can use .filter():
function pickInterval( array, interval ) {
return array.filter( function( _, i ){
return !( i % 3 );
});
}
Of course there's still a loop here, down inside .filter(). It's just been hidden from us in the very same way that pickInterval() hides any loop from its caller.
And that's the real point. Use .filter(), use a for loop, use whatever you want, as long as you encapsulate it inside a function. Then the inner workings of that function don't matter so much. If you like the for loop because it's fast and easy to understand, use that. If you like the filter() version because it's interesting and elegant, use that. If you later need to use it on a very large array and it's running slow, you can replace it with the for loop version without affecting the code that uses pickInterval().
Whatever code you write for this or for something like it, don't put it inline. Make a function.

Categories

Resources