Replace consecutive items in list

Hi

I have a list which looks something like this.

What I am trying to do is replace items which are consecutive and based on a condition (= “LANDING”). So in this scenario, only list 1 should change and be:

0
1 Landing
2
3 Landing
4

What would be the logic to do this? I can get the index of similar items but to determine if these indices are sequential and use that to drive a replace by condition I’m not really sure. I suspect it’s a problem for Python?

Here’s an attempt to tackle it. It could be wrong though. :sweat:
There should be better ways by exploring the Python Library.

List.dyn (13.1 KB)

if you can get the indexes of “Landing”, as long as it’s consecutive, any index should have the same difference with its current index in the sublist.
1 - 0 = 1
2 - 1 = 1
3 - 2 = 1
or another example:
5 - 0 = 5
6 - 1 = 5
7 - 2 = 5

And 1 or 5 happens to be the first num (index of “Landing” in the original sublist). so the delta is the first item (it always minus 0).
image

then check if every num in the sublist has the same delta with its index. Initializing a “Sum” variable, once a check passed, increment the sum. If the “Sum” is equal to the length of the sublist at the end of the loop, then it’s a sublist containing sequential indexes in the previous sublist.

Then identify the nums with odd index, head back to the previous sublist, use the nums as indexes to overwrite things.

This is probably a s*** show of a python script but it works for now:

# Enable Python support and load DesignScript library
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# The inputs to this node will be stored as a list in the IN variables.
mainList = IN[0]
lookFor = IN[1]
boolList = []
temp = []
outMain = []

for insideList in mainList:
	indices = [i for i, x in enumerate(insideList) if x ==lookFor]
	temp.append(indices)		# Appends all indices of lookFor in temp

for i in range(len(temp)):		# Goes through the list of list of indices
	cList = [""]*len(mainList[0])
	try:
		for j in temp[i]:		# Uses the index
			if j in temp[i-1]:	# Checks if the index exists in the following list
				for inside in range(len(mainList[i])):
					if inside == j or cList[j] == True:
						cList[j] = True
	except IndexError:
		pass
	
	try:
		for j in temp[i]:		# Uses the index
			if j in temp[i+1]:	# Checks if the index exists in the following list
				for inside in range(len(mainList[i])):
					if inside == j or cList[j] == True:
						cList[j] = True
	except IndexError:
		pass
	boolList.append(cList)
	
for mB,mM in zip(boolList,mainList):
	outSub = []
	for iB,iM in zip(mB,mM):
		if iB == True:
			outSub.append(lookFor)
		else:
			outSub.append("")
	outMain.append(outSub)
	
OUT = outMain
2 Likes

Haha, bloody hell @kennyb6 :smiley:

You’re getting a like for effort :smiley:

1 Like

Just for the fun of it I gave it a crack using nodes/codeblocks… how would this work?

3 Likes

wow :star_struck:

Has slightly different behavior when used on lists larger than 3, if I am understanding what the OP’s wanted logic is. I also had to update my script to match the logic I will explain below.

This is my assumption of what he wants the script to accomplish:

  • First and last lists should show “LANDING” wherever they originally are, regardless of the lists between them.

Lists inbetween the first and last should only show “LANDING” when “LANDING” exists in the list originally AND with one of the following:

  • “LANDING” occurs at the same index in the previous list or
  • “LANDING” occurs at the same index in the following list

So my python tries to account for the original list capable of handling an infinite amount of lists, hopefully.

Updated python:

# Enable Python support and load DesignScript library
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# The inputs to this node will be stored as a list in the IN variables.
mainList = IN[0]
lookFor = IN[1]
boolList = []
temp = []
outMain = []

for insideList in mainList:
	indices = [i for i, x in enumerate(insideList) if x ==lookFor]
	temp.append(indices)		# Appends all indices of lookFor in temp

for i in range(len(temp)):		# Goes through the list of list of indices
	cList = [""]*len(mainList[0])
	try:
		for j in temp[i]:		# Uses the index
			if j in temp[i-1]:	# Checks if the index exists in the following list
				for inside in range(len(mainList[i])):
					if inside == j or cList[j] == True:
						cList[j] = True
	except IndexError:
		pass
	
	try:
		for j in temp[i]:		# Uses the index
			if j in temp[i+1]:	# Checks if the index exists in the following list
				for inside in range(len(mainList[i])):
					if inside == j or cList[j] == True:
						cList[j] = True
	except IndexError:
		pass
	if i == len(temp)-1 or i == 0:
		for j in temp[i]:
			for inside in range(len(mainList[i])):
				if inside == j or cList[j] == True:
					cList[j] = True
	boolList.append(cList)
	
for mB,mM in zip(boolList,mainList):
	outSub = []
	for iB,iM in zip(mB,mM):
		if iB == True:
			outSub.append(lookFor)
		else:
			outSub.append("")
	outMain.append(outSub)
	
OUT = outMain

The main difference being list 1, item 2. The original list has that as LANDING but neither the list before nor after has that item filled, so it should be removed.

1 Like

I understand your point, and you’re right if that is indeed the intend of the post :slight_smile:

My understanding is that if the item appears in the same location in multiple lists it is “allowed” if not it should be removed :slight_smile: Let’s see what @Paul_Wintour says :slight_smile:

1 Like

Ah that approach makes sense as well. It is hard to tell what the logic is supposed to be with only three lists shown as an example :grinning:

In fact there are four lists in his initial example (therefore my hunch that was the intend) he only shows 3 though :slight_smile:

(20 items, 5 items pr. list, thus 4 lists).

1 Like

Sorry i should have been clearer. The script is dimension through a stair run to create a dimensional string. The stair could have any number of risers so the list length will be variable. For each run (list) there will be a variable amount of reference faces (sub lists).

In order to modify the ‘below text’ I’m preferring the landing face and removing the riser face in case it is co-planar. Using Rhythm I can get the element the dimension is hosted to. If the dimension segments is pointing to TWO landings, that it is a landing, else it is something else so no need to over ride the text. It is pretty straight forward in this scenario.

However here, the list would be:

  • stair
  • landing
  • landing (to be overwritten)
  • landing
  • landing (to be overwritten)
  • landing
  • landing (to be overwritten)
  • stair.

Using my methodology shows the below text incorrect. So the rule I guess is that, if there are consecutive instances (“Landing”), replace with “” in a false/true sequence. I think that’s right…I’ve been looking at this for too long!

So basically what you want is there to not be any consecutive LANDING in a single list?

I too would like a little further information :slight_smile: I don’t quite get what your initial input is and what your expected output is etc. :wink: If I understand that you only want to keep lists which have only one value etc change the “>” to a “<” in my post. But guess it is not that simple.

Does this help?

@kennyb6 yes I believe so.

Then I think my solution should indeed work for you. :slight_smile:

Is this what you mean?


The items in the red box should be removed because it is consecutive?
This is the python, let me know if it works.

# Enable Python support and load DesignScript library
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# The inputs to this node will be stored as a list in the IN variables.
mainList = IN[0]
lookFor = IN[1]
tempInd = []
finalC = []
outList = []

for subList in mainList:
	indices = [i for i, x in enumerate(subList) if x ==lookFor]
	tempInd.append(indices)
	
for subInd,subList in zip(tempInd,mainList):
	tempC = [""]*len(subList)
	for i in range(len(subInd)):		# Uses the index
		if i != 0 and subInd[i] - subInd[i-1] == 1 and tempC[subInd[i-1]] != False:
			tempC[subInd[i]] = False
		else:
			tempC[subInd[i]] = True
	finalC.append(tempC)

for subC in finalC:
	outSub = [""]*len(subC)
	for i in range(len(subC)):
		if subC[i] == True:
			outSub[i] = lookFor
		else:
			outSub[i] = ""
	outList.append(outSub)

OUT = outList

This oughta do it with no Python and just one node :sunglasses:

Had to resort to a while-loop because the for-loop won’t let me manually change the counter…

Also I can’t for the life of me figure out how y’all are posting nicely formatted code! Is there a secret option or some such?

2 Likes

If you paste the code in here, select it and hit this button…

image

It will format :slight_smile:

Hope that helps,

Mark

1 Like

I tried that, I modified my answer nine times, sometimes it just won’t create indentation for the script, and " " is shown as :quote;. :persevere:

You broke it :smiley:

If I copy from your graph I replicate your formatting fail…

indices = [i for i, x in enumerate(lst) if x == &quot;Landing&quot;]

Perhaps someone knows why?!

Mark