Replacing items in a list based on search criteria


#1

Here’s what I’m trying to do. I have a list and want to change those items that do not contain a particular string by appending the search string:

ListQ2

I thought this would be a simple endeavor, but I can’t figure it out and it’s time to solicit some help :slight_smile: As I’m trying out options, I also came across this issue, where I cannot figure out how to reverse the condition list (there’s no “String.DoesNotContain” node!) and since the input is a predicate, you cannot just add the “Not” node after the String.Contains boolean output:

ListQ1

Any help with the above would be great, thanks in advance!

 


#2

Dave, does this work?

Does Not Contain


#3

Ahhh thanks, I was just reading another post mentioning the Function.Compose node but it didn’t give me the desired result because I reversed the functions (oops). I’ll see if I can make some more headway in my original quest now and will post back the result if I succeed.


#4

Well, there doesn’t seem to be a way to do this with nodes. There’s a node in the Clockwork package that comes close, called List.ReplaceItemAtIndex, but then I cannot figure out how to generate the list of indices. I might just go straight to a python solution instead.


#5

Python it is then!

PythonReplace


#6

replacing items on list 2How about this?

 

 


#7

Brilliant, thanks a lot! I think I’m beginning to better understand how functions work: the stream of incoming data in a node that uses functions has to be acceptable input for those functions as well so as each item is processed by each branch, it is computed and passed on to the "final’ node. At least that’s how I’m able to explain it in my head :slight_smile:

I tried another avenue but I couldn’t get the result. I think it’s due to how the List.ReplaceItemAtIndex works. For some reason it rebuilt the list into a list of lists consisting of 4 nested lists, which is what the Index input was. I cannot explain the logic behind it and don’t think there’s a way to do it using this method…unless someone knows of a way?

ReplaceItems


#8

Morning David,

Have you tried the formula node?

2015-05-22_09-57-09


#9

Your Python code indicates that you’re more inclined towards Imperative Programming (IP) than Functional (FP). Dynamo tends to prefer the FP approach, actually in this case even Python would be more optimal going with the FP approach. E.g.

PythonListMap-StringReplace

The Python being:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
#The inputs to this node will be stored as a list in the IN variable.
strList = IN[0]
strSearch = IN[1]

def ReplaceIfNotFound (s):
    if strSearch in s:
        return s
    else:
        return s + strSearch

#Assign your output to the OUT variable
OUT = map(ReplaceIfNotFound, strList)

 

The reason the ReplaceByCondition (and for that matter a List.Map) doesn’t work is something I regard as a bug in Dynamo. The trouble is you generate a “function” to send to the mapping node. This function consists of many nodes taking inputs and calculating a result from those. Now Dynamo builds this function by checking which nodes have empty inputs, those it then deems as the parameters the function requires. So if it sees 2 empty inputs it “knows” the map function needs 2 lists of inputs.

If this wasn’t buggy in current dynamo 8 this one should have worked:

StringReplaceifNotFound-ListCombine

 

 

 

 

See … 3 empty inputs and 3 lists of inputs. But as you can see it simply doesn’t --> bug.

 

Another alternative would be to gather one input and reuse it numerous times like this:

StringReplaceifNotFound-ListMap-Formula

 

 

 

 

Again, there’s an issue, in this case the Formula node changes the type of the input to something other than a String (??? WTF ???). And a Code Block simply results in null objects, same with Object.Identity. I’m not certain of any other means to gather such inputs.

 

However, there is “one” way to “force” Dynamo to understand that your “function” only requires the one input value even though it may be using it numerous times over. That is to make your function in a custom node:

StringReplaceifNotFound-ListMap-CustomNode

 

 

 

Which then works as expected:

StringReplaceifNotFound-ListMap-Custom

 

 

 

 

Strange to have to jump through such hoops to get even just this one simple thing working. I’ve even tried making a custom node which just passes the input as the output so I can collect the List.Map’s function parameter and reuse it many times inside the function. But that also produces null results as Code Blocks and Object.Identity does. This is why I think it’s a bug in Dynamo, at least for now.


#10

Hi Irneb, good observation, this is a UI / interaction problem.

You can force dynamo to understand this kind of thing with Function.Compose, which should let you chain your functions together, it might be kind of tricky for all situations though, and as you have found custom nodes are another way.


#11

Geez I hate this forum. Lack of notifications really stinks! Thanks a lot Dimitar, that is a very simple and effective approach. I need to start collecting examples as there are so many ways to approach the same problem. I’ll read and digest Irneb’s post shortly.


#12

Thanks Irneb, and thanks for the “diagnosis” of my personality :wink: I’ll have to read up a bit more about that topic! In my case I rally reverse-engineered some Python to learn the syntax and then used what I learned to build up this simple solution.

The solution offered above by Rafael using the Function.Compose node is interesting but I’m still trying to fully understand how it can be applied in other cases. I’m finding it a bit hard sometimes to wire things up properly without hours wasted trying several approaches when dealing with lists of things that need processed. I typically see if I can get something to work on one element, then try to figure out how to make changes so it works on lists. I’m finding that challenging in some cases. Dimitar’s solution above was definitely the most traight-forward.

I’ve been trying to avoid custom nodes because it makes things more difficult for others to try if that node is missing, so perhaps I’m missing out on some of the indirect benefits of wrapping things in custom nodes. I just don’t use Dynamo enough to know what I don’t know…you know? :slight_smile: