Replace elements in $lb

Primary tabs

Let's say I have a list structure:

set list = $lb("stri,ng", $c(0), 2)

I want to replace all $c(0) elements with empty elements, so my list would look like:

set list = $lb("stri,ng", , 2)

What's the fastest way to do that?

  • 0
  • 0
  • 244
  • 8
  • 5

Answers

I don't know the fastest way. I know a way:

 set list = $lb("stri,ng", $c(0), 2)
 set list2 = "", ptr = 0
 while $listnext(list, ptr, elem) {
     if elem'=$C(0) {
         set list2 = list2 _ $LB(elem)
     } else {
         set list2 = list2 _ $LB()
     }
 }

I think best way is to use $li to replace the item.

Then you need to set "list" again.

There's documentation on thia.

set list = $lb("stri,ng", $c(0), 2)
   ,p=0
for  set p=$LISTFIND(list,$C(0),p) quit:'p  set $LIST(list,p)=""

Speed comparison:

Class POI.Test
{

/// do ##class(POI.Test).main()
ClassMethod main(rounds As %Integer = 1000, size As %Integer = 10, nullPercent As %Integer = 20)
{
    set list = ..getList(size, nullPercent)
    
    write !,"Rounds: ", rounds
    write !,"Size: ", size
    write !,"NullPercent: ", nullPercent
    write !,"List: "
    zwrite list
        
    set ways = $lb("listnext", "listfind", "lfs", "base")
    for i=1:1:$ll(ways) {
        set way = $lg(ways, i)
        set start = $zh
        
        set list2 = $classmethod(,way, rounds, list)
        
        set end = $zh
        
        set time = end - start
        
        write !,"Way: ", way
        write !,"Time: ", time
        write !,"List: "
        zwrite list2
        write !
    }
}

ClassMethod base(rounds As %Integer = 1000, list As %List) As %List
{
    for i=1:1:rounds {
        set origList = list
    }
    quit origList
}

ClassMethod listfind(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set origList = list
        set ptr=0
        for  set ptr=$LISTFIND(origList, $c(0), ptr) quit:'ptr  set $LIST(origList, ptr, ptr)=$lb()
    }
    quit origList
}

ClassMethod listnext(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set list2 = ""
        set ptr = 0
        while $listnext(list, ptr, elem) {
            if elem'=$C(0) {
                set list2 = list2 _ $LB(elem)
            } else {
                set list2 = list2 _ $LB()
            }
        }
    }
    quit list2
}

ClassMethod lfs(rounds As %Integer = 1000, list As %List)
{
    for i=1:1:rounds {
        set str = $lts(list)
        set str = $tr(str, $c(0))
        set list2 = $lfs(str)    
    }
    quit list2
}

ClassMethod getList(size As %Integer = 10, nullPercent As %Integer = 20) As %List
{
    set list = ""
    for i=1:1:size {
        set list = list _ $lb($select($random(101)<=nullPercent:$c(0),1:$random(50)))
    }
    quit list
}

Results:

POI>do ##class(POI.Test).main(1000000)
 
Rounds: 1000000
Size: 10
NullPercent: 20
List: list=$lb(25,20,$c(0),$c(0),4,42,$c(0),28,44,3)
 
Way: listnext
Time: .944814
List: list2=$lb(25,20,,,4,42,,28,44,3)
 
 
Way: listfind
Time: .610244
List: list2=$lb(25,20,,,4,42,,28,44,3)
 
 
Way: lfs
Time: .430088
List: list2=$lb("25","20","","","4","42","","28","44","3")
 
 
Way: base
Time: .032151
List: list2=$lb(25,20,$c(0),$c(0),4,42,$c(0),28,44,3)

listfind solution seems optimal.

Ed, it's not about speed, but about syntax sugar on "for cycles". you can go like that: 

 
/// do ##class(POI.Test).main() 
ClassMethod main(rounds As %Integer = 1000, size As %Integer = 10, nullPercent As %Integer = 20) {
 set list = ..getList(size, nullPercent) 
 write !,"Rounds: ", rounds 
 write !,"Size: ", size 
 write !,"NullPercent: ", nullPercent 
 write !,"List: " 
 zwrite list
for way="listnext", "listfind", "lfs", "base" {

  set start = $zh set list2 = $classmethod(,way, rounds, list)

  set end = $zh set time = end - start 
 write !,"Way: ", way 
 write !,"Time: ", time 
write !,"List: "
 zwrite list2

  write ! }

Elaborated ;) Full classmethod Main() now.

You can get rid of two lines:

set ways = $lb("listnext", "listfind", "lfs", "base")

and

set way = $lg(ways, i)

if you change for to:

for way="listnext", "listfind", "lfs", "base" {

Do not forget that $lb is just a list, concatenated list of single $lb, and $lb is a string in binary format.. So, just $replace, will work

USER>set list = $lb("stri,ng", $c(0), 2)

USER>set list = $replace(list, $lb($c(0)), $lb())

USER>zw list
list=$lb("stri,ng",,2)

Unless you have list with $c(3,1,0) as element

USER>set list = $lb("stri,ng", $c(0), 2, $c(3,1,0), 3)

USER>set list = $replace(list, $lb($c(0)), $lb())

USER>zw list
list=$c(9,1)_"stri,ng"_$c(1,3,4,2,5,1,1,3,4,3)

USER>w $LL(list)

W $LL(list)
^
<LIST>

Here's a somewhat contrived case where that technique fails:

USER>s weirdlist=$lb("Very "_$lb($c(0))_" odd data",$c(0),2)
 
USER>s replaced=$replace(weirdlist,$lb($c(0)),$lb())
 
USER>zw weirdlist
weirdlist=$lb("Very "_$c(3,1,0)_" odd data",$c(0),2)
 
USER>zw replaced
replaced=$c(19,1)_"Very "_$c(1)_" odd data"_$c(1,3,4,2)
 
USER>