Skip to main content

Hi,

I haven’t been able to find this question asked anywhere, but I’m sure it has been. I’m at a lost though. I have a unique attribute in a group of features. I wish to find unique combinations of all possible pairs in my group of features.

For example, if I have three features. Their ID’s are 1, 2, and 3. The result I want to find is a feature with a new ID of: 1-2, 1-3, and 2-3

In reality my groups can be up to 20 features in size.

I can’t work out how to accomplish this in FME. Though I’m sure its very easy.

Does anyone know how I would do this?

Easiest is to use CROSS JOIN in an InlineQuerier SQL Statement

 

Note, the “WHERE” is optional but puts a filter for only where A.ID and B.ID are different values.  Remove it if also want ID values to intersect with themselves.

 

SELECT A.ID AS A_ID, B.ID AS B_ID
FROM A CROSS JOIN B
WHERE A.ID <> B.ID

 

Input

 

 

 

 

Further, if A and B actually come from the same table/features, then can simplify/make even faster by just CROSS JOINing “Data” to itself with below.

Also shown example of how to derive a “NewID” in the same step using SQLite’s Concantenation operator || , however can do this just as easily outside the SQL in an AttributeCreator.

SELECT A.ID AS A_ID, B.ID AS B_ID, A.ID||'-'||B.ID AS NewID
FROM Data A CROSS JOIN Data B
WHERE A.ID <> B.ID

 

If further want only unique groupings rather than just all pair permutations then change the WHERE to only give WHERE A.ID is < B.ID.   This will then give “1-3” but will remove “3-1” from the output.

 

SELECT A.ID AS A_ID, B.ID AS B_ID, A.ID||'-'||B.ID AS NewID
FROM Data A CROSS JOIN Data B
WHERE A.ID < B.ID

 

Alternatively, because I generally recommend FeatureJoiner over FeatureMerger for performance, then can do it a slightly longer way by creating a “Cross Join” Attribute
 

 


I really like the solution from @bwn , but just for fun, here’s the same using a single PythonCaller:

import fme
import fmeobjects
from itertools import combinations


class GetCombinations(object):
"""Template Class Interface:
When using this class, make sure its name is set as the value of the 'Class to Process Features'
transformer parameter.
"""

def __init__(self):
"""Base constructor for class members."""
self.ids = ]

def has_support_for(self, support_type: int):
"""This method is called by FME to determine if the PythonCaller supports Bulk mode,
which allows for significant performance gains when processing large numbers of features.
Bulk mode cannot always be supported.
More information available in transformer help.
"""
return support_type == fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM

def input(self, feature: fmeobjects.FMEFeature):
"""This method is called for each feature which enters the PythonCaller.
Processed input features can be emitted from this method using self.pyoutput().
If knowledge of all input features is required for processing, then input features should be
cached to a list instance variable and processed using group processing or in the close() method.
"""
# Add current id to list of all ids
id = str(feature.getAttribute('id'))
self.ids.append(id)

def close(self):
"""This method is called once all the FME Features have been processed from input()."""
# Generate all possible combinations, modify the number "2" below to change
# the length of the combinations allowed
combis = '-'.join(item) for item in combinations(self.ids, 2)]
for combi in combis:
feature = fmeobjects.FMEFeature()
feature.setAttribute('result', combi)
self.pyoutput(feature)

def process_group(self):
"""This method is called by FME for each group when group processing mode is enabled.
This implementation should reset any instance variables used for the next group.
Bulk mode should not be enabled when using group processing.
More information available in transformer help.
"""
pass

 


Yet another solution: on FME Hub you can find ListSubsetEnumerator. This custom transformer lets you create permutations, combinations and multicombinations of items in a list.

Under the hood this custom transformer uses a python script.

 


Wow, thanks for the comprehensive replies everyone. They all work perfectly


Reply