Deleting Array Element By Number

I was working on a small development issue today where the client wanted to be able to select a value from a multi-value list and then remove that entry and entries in the same position from a number of other multi-value lists.

The existing code for this function was written in Formula language and it just didn’t work properly so I set about rewriting it in LotusScript. A much neater solution…

First a small shared function…

Function removeElement(varFromList As Variant,varTarget As Integer) As Variant Redim arrReturn(0) As Variant Dim intCount As Integer intCount=0 For element = Lbound(varFromList) To Ubound(varFromList) If element <> varTarget Then Redim Preserve arrReturn(intCount) As Variant arrReturn(intCount)=varFromList(element) intCount=intCount+1 End If Next element removeElement=arrReturn End Function

Then to call the function it’s just a simple bit of code

Selection = w.Prompt(4,"Select Part To Remove","Please select the part number _
that you wish to remove from the list"
,"",doc.part) If Selection = "" Then Exit Sub SelectionNo = Arraygetindex(doc.Part,Selection) doc.Part = removeElement(doc.Part,SelectionNo)
This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.
Tagged with:
Posted in Uncategorized
8 comments on “Deleting Array Element By Number
  1. Declan Lynch says:

    Thanks for the ‘formula language’ version Robert. The one that was in the database I was using was so unreadable that I couldn’t make head nor tail of of it. I think the LotusScript version is nicer however when you have a load of fields to do.

    I needed to get rid of a ‘Part’ listing across 6 fields. Part, Quantity, Unit Price etc. With the script version you just have to write the function once and then call it for each field you want to remove the element from.

    Like

  2. Nathan T. Freeman says:

    Oh, for shame, Declan! Surely a developer of your caliber can see when he’s coding a base function with bad performance aspects. Sure, if your multi-value list has 5 elements, we probably won’t care. But make it 1000 or so and see what happens with your removeElement function!

    Because I want our latest OpenNTF star to give good advice to his audience, let’s optimize. 🙂

    First, you’ve got a Redim Preserve. Now in general, a Redim Preserve is to be avoided, but what’s really important is to avoid it INSIDE a loop. If you’ve got 5 elements, you’re reallocating and building the array in new memory 4 times with this function. But if you’ve got 1000, you’re reallocating and populating memory 999 times! Try doing that on a scalable web page!

    In truth, the fact that your only removing a single element with this function means you can make it super-efficient. You know that you’re going to end up with an array that’s the original size minus one, so there’s all kinds of neat tricks we can do with that.

    If we were willing to accept that we’re always going to modify the original array, we could even remove the element in place. Which would be a huge benefit if we want to remove element 999 of 1000.


    Function removeElement(varFromList As Variant,varTarget As Integer) As Variant
    Dim intCount As Integer
    intCount = varTarget
    For element = varTarget To Ubound(varFromList)-1
    intCount=intCount+1
    varFromList(element)=varFromList(intCount)
    Next element

    varFromList(ubound(varFromList)) = “” ‘we might want to check for numeric data, etc

    fullTrim(varFromList)

    removeElement=varFromList
    End Function

    But even if we don’t, we only have to set the size of the new array once. And we can make our loop more efficient by avoiding the (admittedly simple) comparison and counter.


    Function removeElement(varFromList As Variant,varTarget As Integer) As Variant
    Dim newArray() as Variant
    Redim newArray(ubound(varFromList)-1)

    For element = lbound(varFromList) to varTarget-1
    newArray(element) = varFromList(element)
    Next element

    For element = varTarget+1 To Ubound(varFromList)
    newArray(element-1) = varFromList(element)
    Next element

    removeElement=newArray
    End Function

    That’s it. There’s probably more to be done, but the point is, base functions like these should be coded with maximum efficiency, because they’re exactly the sort of thing that you put in a library and call 50 times on a single page. Then you deploy your Domino server, have 1000 people simultaneously connecting and you want to make sure that you’re not killing your performance with unnecessary memory allocation on a grand scale.

    Hope this helps!

    Like

  3. Robert Basic says:

    here the formula in R5:

    1. case = use this if there could be same entries in list (like A:A:A:B:C)
    – a field called DelElement/number => user enters to be removed element
    – two multivalue fields, called “ListA” and “ListB”
    – a button with that formula:

    REM “which element to delete”;
    var_element:=DelElement;

    REM “Get multivalues from Field A and B”;
    var_SourceA:=ListA;
    var_SourceB:=ListB;

    REM “some logical checks”;
    @If(var_element>@Elements(var_SourceA);@Return(@Prompt([OK];”ayiieee”;”entered element number greater then number of entries!”));@Success);
    @If(@Elements(var_SourceA)>@Elements(var_SourceB);@Return(@Prompt([OK];”ayiieee”;”number of entries in Field A and Field B is different!”));@Success);

    REM “build new list, e.g. if 7th element to be removed then at first subset element 1-6 and than elements 8-10″;
    var_NewListA:=
    @trim(
    @If(var_element < 2;””;@Subset( var_SourceA; var_element – 1 )) :
    @If(var_element = @elements( var_SourceA );””; @Subset( var_SourceA; var_element – @elements( var_SourceA )))
    ) ;

    var_NewListB:=
    @trim(
    @If(var_element < 2;””;@Subset( var_SourceB; var_element – 1 )) :
    @If(var_element = @elements( var_SourceB );””; @Subset( var_SourceB; var_element – @elements( var_SourceB )))
    ) ;

    Field ListA:=var_NewListA;
    Field ListB:=var_NewListB;

    void

    2. case = use this if there are guaranteed no same entries in list (like A:B:C:D:E)

    REM “which element to delete”;
    var_element:=DelElement;

    REM “Get multivalues from Field A and B”;
    var_SourceA:=ListA;
    var_SourceB:=ListB;

    REM “some logical checks”;
    @If(var_element>@Elements(var_SourceA);@Return(@Prompt([OK];”ayiieee”;”entered element number greater then number of entries!”));@Success);
    @If(@Elements(var_SourceA)>@Elements(var_SourceB);@Return(@Prompt([OK];”ayiieee”;”number of entries in Field A and Field B is different!”));@Success);

    REM “identify given element in Field A and B to be replaced”;
    var_WhatA:=@Subset(@Subset(ListA;var_element);-1);
    var_WhatB:=@Subset(@Subset(ListB;var_element);-1);

    REM “replace element in Field A and B”;
    var_newListA:=@Trim(@Replace(var_SourceA ; var_WhatA; “” ));
    var_newListB:=@Trim(@Replace(var_SourceB ; var_WhatB; “” ));

    FIELD ListA:=var_newListA;
    FIELD ListB:=var_newListB;

    _void

    Like

  4. Declan Lynch says:

    Robert, the fulltrim method would work ok provided that there are no other parts of the array with null values. If there is the possibility of null values in the array then FullTrim will get rid of them all.

    Nathan, Yes, the method that you have described would be much better, especially for large arrays. I never said my function had been optimised, it just did what it needed in the clients database. When I’m back in there today I might change it to your version.

    Like

  5. Robert Basic says:

    just a small question..ermm..im really not the big developer as you guys are, but does this code does not do the same and faster:

    Dim WS As New NotesUIWorkspace
    Dim UIDoc As NotesUIDocument
    Set UIDoc = ws.CurrentDocument
    Dim Doc As NotesDocument
    Set doc = uidoc.document
    dat = doc.MV
    dat(0) = “”
    datnew = Fulltrim(dat)
    doc.MV = datnew

    Call doc.save(True, False)

    You could simply call the bold part into a function. No redims, no For loops, …am i overlooking something or is it so easy? I mean, Declan wants to remove a given element by an index.

    Like

  6. arrResult=FullTrim(ArrayReplace(arrRemoveFrom, arrRemoveThis,{})):-)

    Like

  7. Robert Basic says:

    im throwing Script away wherever i can due to perfomance aspects. In this case you are absolutely right with it: Script serves better than Formula. Just wanted to throw it in since there are always Domino guys/girls w/o Scripting know how.

    btw…did you see the new R6 formulas? wow….i will try to translate your script into the new R6 environment.

    cu

    Rob

    Like

  8. Sorry, didn’t read the latest posting…I admit if you need to preserve null values you’re into trouble…Maybe use ArrayAppend? But how to map e.g. arr(42..53) to arr(0..11) effectively w/o addressing each element? If there’s a way we can Redim Preserve array1 to 0..40, omit 41 and ArrayAppend arr(42..53).Sometimes lists are much easier to handle.. we could just use Erase(tag) and be done with it.Wolfgang

    Like

Comments are closed.

Archives