web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

Community site session details

Community site session details

Session Id :
Power Platform Community / Forums / Power Apps / Optimizing Sorting and...
Power Apps
Suggested Answer

Optimizing Sorting and Filtering large collection

(1) ShareShare
ReportReport
Posted on by 674
I have a collection with about 400 records. In my app, each time I move an item in or out of the collection, the Items property needs to re-sort and re-filter, even though I am only moving a single item at a time.  This results in 800 actions (400 sortby and 400 filter), totaling 3 to 5 seconds of time.
 
Is there any way to optimize the sorting and filtering to make it run faster?
 
SortByColumns(
Filter(AheadWithDates,
If(IsBlank(PieceUIDSearch.Selected.ElementNo), Not(PieceUIDSearch.Selected.ElementNo in DATA.ElementNo), PieceUIDSearch.Selected.ElementNo in DATA.ElementNo)
And TotalWtLoadSum > 10 And If(IsBlank(LotNumSearch.Selected.Value), Not(LotNumSearch.Selected.Value in DATA.LotNumber), LotNumSearch.Selected.Value in DATA.LotNumber)),
"DelDateSort",
SortOrder.Ascending,
"ExtStackContainerNo",
SortOrder.Ascending
)
 
Categories:
I have the same question (0)
  • Suggested answer
    Michael E. Gernaey Profile Picture
    53,442 Super User 2025 Season 2 on at
    Hi @55552
     
    Sorry for your troubles. IK have a huge favor (its for me since my old eyes have issues). Can you use the Code Snippet to put code in.
     
    Its the second to last icon 
     
    That being said, thank you so much for putting the text so I can copy it out :-) 
     
    Now if I understand, you say you are moving things in and out. Just to clarify are you saying that you remove them completely and then put them back, or add new ones?
     
    What I would like to suggest is for instances where
    * You take things out and might put them back
    * You have X in there but only want to show Y
     
    I would add another boolean column which is easy to filter on, or an Int (just dont use a string).
    Essentially if something needs to be moved outk, don't move it out, set it to false or like #1
    then in your filters to show the data, just add in where 0 means show it, and 1 means dont, but its better to do = instead of <> 
    or use a boolean like below and set it to true (to show it) or false not too
     
    but since you dont remove them, there are no resorts 
    And NewInt = 0
    or
    And NewBoolean = true
     
    This way your sorts still work the same so filtering etc shouldn't be impacted, because you can filter initially WITHOUT the above new column, but then sub filter that result with the new column to create an even smaller one.
     
    Does that make sense?
     
    Did that cover your scenario? Or do you have more specific ones. In this case, essentially the only time it should be impacted, if you totally fill your collection of 400 items (or 800 or whatever) is when you add new ones and your sorts are done.
     
    Also another thing
     
    You can always use an intermediate.
     
    What I mean is. Imagine like a Gallery. And you Populate it with a Collection.
    Now you add 10 rows to the collection and filter and sort and now the Gallery "blinks and blips" because the data is changing
     
    Instead, change an intermediate like
    ClearCollect(_mytempcollection, dosomething)
    Now none of your galleries etc change
     
    Then when you are all done doing sorts etc
    ClearCollect(myrealcollection, _tempcollection)
    Please let me know if any of this helps or if you need more examples or just want to bounce ideas.
     
  • 55552 Profile Picture
    674 on at
    @Michael E. Gernaey Thanks so much for the detailed response. I put the code snippet into the editor and modified the post. Here is some more detail on this app.  I think your idea is on the right track. My wording about moving items in and out of the collection was not quite correct. The collection items are remaining the same, but a column in the collection changes from a ZoneID (will explain later) of Date|Time to "Unassigned" or the reverse of that.

     am using a custom control built by Scott Durow called DragDrop (GitHub - scottdurow/power-drag-drop), which allows dragging and dropping of items from a "zone" to another "zone" on the screen. When the items are "dropped," the code then modifies the collection by changing the ZoneID column to either "Unassigned" (dragged into the original list on the right) or a ZoneID (a combination of Date|Time). 
     
    Even though the number of items in the collection is not actually changing during this action, I have used the monitor function, and for every item/row in the Collection, the SortbyColumns and Filter action is repeated.  They take from 1 to 5 milliseconds each, so it adds up.

    A screenshot of the app is shown below.  Zone setup is fairly complex, with three different dragdrop zone components, nested containers and galleries.

    Overall, this works as expected, but I am trying to make the experience better for the end user, so they do not experience a significant delay after the drag/drop of an item. I do have filters at the top where they can search the items and select from the dropdowns. This typically reduces the number of visible items to one or two, after which the drag/drop is almost instantaneous.
     
    The code that occurs after an item is dragged/dropped is shown below.  This part runs fast, since it is only dealing with the single item that is being dragged and dropped. The filtering and re-sorting takes some time.
    //This works, but slow, takes up to 5 or 6 seconds for larger loads
    Set(varCountMovedZone, CountRows(Filter(ListTasksDrop.CurrentItems, HasMovedZone = true)));
    ForAll(
        Filter(ListTasksDrop.CurrentItems, HasMovedZone = true) As TaskAssignment,
    Patch(AheadWithDates, //was Patch(AheadWithDates,
        LookUp(AheadWithDates, LoadNumText = TaskAssignment.ItemId), //previously LdTaskId = TaskAssignment.ItemId, but no matches in AheadWithDates
        With(
            {
                StartDate: dtpStartDate.SelectedDate,
                ZoneData: Split(TaskAssignment.DropZoneId, "|"),
                Unassigned: TaskAssignment.DropZoneId = "unassigned",
                SeqNo: LookUp(SeqDates, RowDate = DateValue(First(Split(TaskAssignment.DropZoneId, "|")).Value)),
                varReqDate: If(TaskAssignment.DropZoneId = "unassigned", Blank(), DateAdd(dtpStartDate.SelectedDate, LookUp(SeqDates, RowDate = DateValue(First(Split(TaskAssignment.  
                      DropZoneId, "|")).Value)).Sequence -1, TimeUnit.Days) + TimeValue(LookUp(colqtrTime, Time =
                      (Last(Split(TaskAssignment.DropZoneId, "|")).Value), Time))),
                varDateOnly: If(TaskAssignment.DropZoneId = "unassigned", Blank(), DateAdd(dtpStartDate.SelectedDate, LookUp(SeqDates, RowDate = DateValue(First(Split(TaskAssignment.  
                      DropZoneId, "|")).Value)).Sequence -1, TimeUnit.Days))
            },
            {
              Zone: TaskAssignment.DropZoneId,
              Edited: true,//sets edited to true so only edited loads will be saved to Dataverse
              UserRqDate: Now(),
              /*try variabbles from above instead of code
              ReqDate: If(Unassigned, Blank(), DateAdd(StartDate, SeqNo.Sequence -1, TimeUnit.Days) + TimeValue(LookUp(colqtrTime, Time =
                (Last(ZoneData).Value), Time))),
              DelivDate: If(Unassigned, Blank(), DateAdd(StartDate, SeqNo.Sequence -1, TimeUnit.Days) + TimeValue(LookUp(colqtrTime, Time =
                (Last(ZoneData).Value), Time))),
              ReqDateOnly: If(Unassigned, Blank(), DateAdd(StartDate, SeqNo.Sequence -1, TimeUnit.Days)),
              */
              ReqDate: varReqDate,
              DelivDate: varReqDate,
              ReqDateOnly: varDateOnly,
              ReqDateSort: varReqDate,
              ReReq: "No"//for any movement of loads, ReReq is set back to "No"  
                                
            }   
            )//end of With
        )//end of patch
    ); //end of ForAll
     
  • Suggested answer
    Michael E. Gernaey Profile Picture
    53,442 Super User 2025 Season 2 on at
    Hi @55552
     
    I will talk a look, but there is something wrong with this code.
     
    When I copy it and paste it, it is missing a ) at the end and the comments like // end ForAll are inaccurate. Feel free to double check, but the last ) closes the patch, there isn't one for the ForAll.
     
    Ok set the aside
     
    First Question
     
    1. Why are you doing a Double Filter on the exact same data
    Set(varCountMovedZone, CountRows(Filter(ListTasksDrop.CurrentItems, HasMovedZone = true)));
     
    Then
    ForAll(
        Filter(ListTasksDrop.CurrentItems, HasMovedZone = true) As TaskAssignment,
     
    That alone will add time, since you don't need it twice
     
    There is a lot going on here both in lookups and expressions (splits etc) for every single record
     
    You should look at doing some of these things inside Concurrency instead of doing everything indvidually.

    You are also doing this multiple times
    LookUp(SeqDates, RowDate = DateValue(First(Split(TaskAssignment.DropZoneId
     
    I mean there are many duplications of work that are causing significant processing for no reason. I would re-write this pretty much totally. I'd also have to review your data structures and see where, instead of doing lookups and splits etc, that I would simply AddColumns to existing data so its just there, versus looping and building it.
     
  • Suggested answer
    Michael E. Gernaey Profile Picture
    53,442 Super User 2025 Season 2 on at
    Hello @55552
     
    I am adding some more. Please take into consideration that I cannot test this, so I am having to type some of this and expect that you can validate it as I am doing it in my head and visualizing it happening there.
     
    So, let's play around, then focus on sorting and filtering (call that part 2 ok)
     
    Truthfully I was imply too... lol ugged looking at it now to try to help you :-), as its a lot to ask.
     
    I still feel if I understood the data better I could do more on this part, but I removed a massive amount of duplication in looks ups and calcs and DateValue expressions.
     
    Please let me know first if this works and we can keep going with the sorts and filters.
     
    We should test the performance difference between this and your old stuff.
     
    I removed several lookups, filters, expressions, calculations etc so if measured correctly, you should see a solid increase in performance just here alone.
     
    ForAll(
    	With(
    	   { TaskAssignment: Filter(ListTasksDrop.CurrentItems, HasMovedZone = true) },
    
    		Set(varCountMovedZone, CountRows(TaskAssignment)); 
    		
    		Patch(AheadWithDates, 
    			LookUp(AheadWithDates, LoadNumText = TaskAssignment.ItemId), 
    				With(
    					{
    						ZoneData: Split(TaskAssignment.DropZoneId, "|"),
    						
    						Unassigned: TaskAssignment.DropZoneId = "unassigned"
    					},
    				
    					With(
    						{
    							StartDate: dtpStartDate.SelectedDate,
    							
    							SeqNo: LookUp(SeqDates, RowDate = DateValue(First(ZoneData).Value)),
    					
    						},
    						
    						With(
    								{
    									varReqDate: If(Unassigned, Blank(), 
    												DateAdd(dtpStartDate.SelectedDate, SeqNo.Sequence -1, TimeUnit.Days) + TimeValue(LookUp(colqtrTime, Time = (Last(ZoneData).Value), Time))),
    										
    									varDateOnly: If(Unassigned, Blank(), DateAdd(dtpStartDate.SelectedDate, SeqNo.Sequence -1, TimeUnit.Days))
    											
    								},
    							
    								{
    									  Zone: TaskAssignment.DropZoneId,
    									  Edited: true,
    									  UserRqDate: Now(),
    									  ReqDate: varReqDate,
    									  DelivDate: varReqDate,
    									  ReqDateOnly: varDateOnly,
    									  ReqDateSort: varReqDate,
    									  ReReq: "No"//for any movement of loads, ReReq is set back to "No"  
    													
    								}   
    						);
    					);
    				);
    		);		
    	);
    )//end of ForAll 
    
     
  • 55552 Profile Picture
    674 on at
    I will remove the set variable statement. It was only temporary so I could see how many rows were in the ListTasksDrops.CurrentItems filtered list. As I thought, there is only a single row, since the filter is just looking at the single item that was dragged and dropped. So even though a ForAll is used, the loop is only over one record. This part of the code executes rapidly, a fraction of a second. The monitor shows almost no elapsed time, so there isn't much room for efficiency here.

    The Items part of the code, where the list refreshes after each drag drop (starting with SortByColumns), is where the code can take 2 or 3 seconds when I have 400 items. And some lists in the app might be longer than that.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Forum hierarchy changes are complete!

In our never-ending quest to improve we are simplifying the forum hierarchy…

Ajay Kumar Gannamaneni – Community Spotlight

We are honored to recognize Ajay Kumar Gannamaneni as our Community Spotlight for December…

Leaderboard > Power Apps

#1
WarrenBelz Profile Picture

WarrenBelz 739 Most Valuable Professional

#2
Michael E. Gernaey Profile Picture

Michael E. Gernaey 343 Super User 2025 Season 2

#3
Power Platform 1919 Profile Picture

Power Platform 1919 268

Last 30 days Overall leaderboard