[Closed] Speedup remove duplicate item from listview
Hello together,
I have a here a loop what search for duplicate filenames from listview items and delete them. I use it for a list of textures in the scene. When I have not so much textures in the scene the script is fast enough, but when it gets more it need long.
So maybe you know a better method to do that?
mL.Sorting = sortOrder.Ascending;
filterStart = timeStamp()
for i = 0 to mL.items.count - 1 do (
for j = mL.items.count - 1 to i+1 by -1 do (
if mL.items.item[i].tag.value[3] != 0 do (
if mL.items.item[i].tag.value[1].filename == mL.items.item[j].tag.value[1].filename do (
mL.Items.RemoveAt[i]
)
)
)
filterStamp = timeStamp()
if ( ( ( filterStamp - filterStart ) / 1000.0 ) >= 4.00 ) do (
filterStart = timeStamp()
windows.processPostedMessages()
)
)
mL is my dotnet listview.
You see what is the problem, for every item it loops complete truth the array.
what are the good and the bad numbers?
for example,
<1000> nodes, <200> dups = < … secs is good … > … secs is bad
it will be better do not add duplicates to the list… but it you couldn’t do it or it might happen it’s better to collect the list again with no duplicates:
collect textures in a uniform format (e.g., lower case, forward single slash)
make unique array
populate the list view
I have here a scene with 970 Textures (without duplication), this needs 80.947 seconds for this process.
When I let fill the listview with all material, submaterials, maps and texture, it need without sorting and filter duplications only 0.792 seconds.
But what you say before make sence, I will try it like this. Is not so easy because I filter with checkboxes witch types get in the listview. the loop for that looks like so:
for m = 1 to colMats.count do (
if ( chkMat.checked == true AND colMats[m][2] == "mat" ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" colMats[m][1].name
li.tag = dotnetMXSValue #(colMats[m][1], "mat")
li.backColor=li.backColor.fromARGB (liCol.r + 20) (liCol.g + 10) (liCol.b + 10)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
join listBG #( colMats[m][1] )
) else if ( chkSub.checked == true AND colMats[m][2] == "sub" ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " " + colMats[m][1].name )
li.tag = dotnetMXSValue #(colMats[m][1], "sub")
li.backColor=li.backColor.fromARGB (liCol.r + 30) (liCol.g + 30) (liCol.b + 20)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
join listBG #( colMats[m][1] )
) else if ( chkMap.checked == true AND colMats[m][2] == "map" ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " " + colMats[m][1].name )
li.tag = dotnetMXSValue #(colMats[m][1], "map")
li.backColor=li.backColor.fromARGB (liCol.r + 30) (liCol.g + 30) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
join listBG #( colMats[m][1] )
) else if ( chkTex.checked == true AND colMats[m][2] == "tex" ) then (
if ( colMats[m][1].filename == undefined OR colMats[m][1].filename == "" ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " ! Warning: empty bitmap texture !" )
li.tag = dotnetMXSValue #(colMats[m][1], "tex", 0)
) else (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " " + filenameFromPath colMats[m][1].filename )
li.tag = dotnetMXSValue #(colMats[m][1], "tex")
)
li.backColor=li.backColor.fromARGB (liCol.r + 40) (liCol.g + 50) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
join listBG #( colMats[m][1] )
) else if ( chkmissing.checked == true AND colMats[m][2] == "tex" ) then (
if ( colMats[m][1].filename == undefined OR colMats[m][1].filename == "" ) then (
if ( chkTex.checked == true ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " ! Warning: empty bitmap texture !" )
li.tag = dotnetMXSValue #(colMats[m][1], "tex", 0)
li.backColor=li.backColor.fromARGB (liCol.r + 40) (liCol.g + 50) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
) else (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " ! Warning: empty bitmap texture !" )
li.tag = dotnetMXSValue #(colMats[m][1], "tex", 0)
li.backColor=li.backColor.fromARGB (liCol.r + 40) (liCol.g + 50) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
)
join listBG #( colMats[m][1] )
) else if not ( doesFileExist colMats[m][1].filename ) then (
if ( chkmissing.checked == true ) then (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " " + filenameFromPath colMats[m][1].filename )
li.tag = dotnetMXSValue #(colMats[m][1], "tex")
li.backColor=li.backColor.fromARGB (liCol.r + 40) (liCol.g + 50) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
) else (
li=dotNetObject "System.Windows.Forms.ListViewItem" ( " " + filenameFromPath colMats[m][1].filename )
li.tag = dotnetMXSValue #(colMats[m][1], "tex")
li.backColor=li.backColor.fromARGB (liCol.r + 40) (liCol.g + 50) (liCol.b + 40)
li.ToolTipText = classof colMats[m][1] as string
append listVis li
)
join listBG #( colMats[m][1] )
)
)
)
Is a bit heavy :)… I will see what I do here.
try(destroydialog lvTest) catch()
rollout lvTest "" width:200
(
local itemscount = 2000
local uniques = 1000
dotnetcontrol lv "ListView" width:192 height:186 pos:[4,4]
button bt "Delete Duplicates" width:192 align:#left offset:[-9,0]
on bt pressed do
(
t1 = timestamp()
count = lv.items.count
nodups = #()
count = lv.items.count
global okitems = for k=0 to count-1 where appendifunique nodups (i = lv.items.item[k]).text collect i
lv.BeginUpdate()
lv.items.Clear()
lv.items.AddRange okitems
lv.EndUpdate()
format ">> items:% dups:% time:%
" count (count - okitems.count) (timestamp() - t1)
)
on lvTest open do
(
lv.BeginUpdate()
lv.view = lv.view.Details
lv.columns.add "Name"
for k=1 to itemscount do lv.items.add (formattedprint (random 1 uniques) format:"04d")
lv.EndUpdate()
)
)
createdialog lvTest
check this snippet… it takes 0.3 sec to remove all duplicates. i’m using item’s text, but you can use whatever you want with the same technique (tag value, key, etc.).
Ah thank you denisT! This makes a speedup with 99%
The only thing what not works is this
(i = mL.items.item[k].tag.value[1]).filename
But is ok, I give the item the name from the filename and work with that.
Is it better to put the lv.items.count in a variable? I use it directly in the loop because I only need it one time.