DedupBy
This transformer will remove elements of the array that contain an identical combination of values for the keys given.
python · Filters And Transformers
Source
import json from typing import Any import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 def demisto_get(obj: Any, path: Any) -> Any: r""" This is an extended function of demisto.get(). The `path` argument parameter supports a syntax of path escaped with backslash in order to support a key including period characters. e.g. xxx + x.y.z + zzz -> path: xxx.x\.y\.z.zzz :param obj: The root node. :param path: The path to get values in the node. :return: The value(s) specified with `path` in the node. """ def split_context_path(path: str) -> list[str]: """ Get keys in order from the path which supports a syntax of path escaped with backslash. :param path: The path. :return: The keys whose escape characters are removed. """ nodes = [] node = [] itr = iter(path) for c in itr: if c == "\\": try: node.append(next(itr)) except StopIteration: node.append("\\") elif c == ".": nodes.append("".join(node)) node = [] else: node.append(c) nodes.append("".join(node)) return nodes if not isinstance(obj, dict): return None for part in split_context_path(path): if obj and part in obj: obj = obj[part] else: return None return obj class Key: """ The custom key object class, which enables you to compare any types of data even in different types. This can be used for keys of dict. """ def __init__(self, value: Any, path: Optional[str] = None) -> None: """ Initialize the key. :param value: The value to set key, or the node from which to get the value if the `path` is given. :param path: The path to get values in the node. """ self.__value = value if path is None else demisto_get(value, path) def __eq__(self, other: Any) -> bool: def __equals(obj1: Any, obj2: Any) -> bool: if type(obj1) != type(obj2): # noqa: E721 return False elif isinstance(obj1, dict): for k1, v1 in obj1.items(): if k1 not in obj2: return False if not __equals(v1, obj2[k1]): return False return not (set(obj1.keys()) ^ set(obj2.keys())) elif isinstance(obj1, list): if len(obj1) != len(obj2): return False return all(__equals(e1, e2) for e1, e2 in zip(obj1, obj2)) else: return obj1 == obj2 if not isinstance(other, Key): return False return __equals(self.__value, other.__value) def __hash__(self) -> int: """ Generate hash using json.dumps for better performance. This replaces the recursive __get_hash_base approach with O(n) complexity. """ try: # Use json.dumps with sort_keys for consistent hashing of dicts # This is O(n) instead of O(n*m) for the recursive approach json_str = json.dumps(self.__value, sort_keys=True, default=str) return hash((type(self.__value).__name__, json_str)) except (TypeError, ValueError): # Fallback for non-JSON-serializable objects return hash((type(self.__value).__name__, str(self.__value))) def main(): try: args = assign_params(**demisto.args()) if value := args.get("value", []): temp = {} if paths := argToList(args.get("keys")): for v in value: k: tuple | Key = tuple(Key(v, path) for path in paths) if k not in temp: temp[k] = v else: for v in value: k = Key(v) # noqa: F812 if k not in temp: temp[k] = v value = list(temp.values()) return_results(value) except Exception as err: # Don't return an error by return_error() as this is transformer. raise DemistoException(str(err)) if __name__ in ("__builtin__", "builtins", "__main__"): main()
README
This transformer will remove elements of the array that contain an identical combination of values for the keys given.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | transformer, general |
| Cortex XSOAR Version | 6.8.0 |
Inputs
| Argument Name | Description |
|---|---|
| value | The array to deduplicate |
| keys | Comma-separated list of keys to identify a value |
Outputs
There are no outputs for this script.
Examples-1
Here is a table to be used as samples in the Examples-1.
| DestinationIP | SourceIP |
|---|---|
| 1.1.1.1 | 192.168.1.1 |
| 1.1.1.1 | 192.168.1.1 |
| 1.1.1.1 | 192.168.1.2 |
| 1.1.1.1 | 192.168.1.2 |
| 1.1.1.1 | 192.168.1.3 |
| 1.1.1.1 | 192.168.1.3 |
| 2.2.2.2 | 192.168.1.1 |
| 2.2.2.2 | 192.168.1.1 |
| 2.2.2.2 | 192.168.1.2 |
| 2.2.2.2 | 192.168.1.2 |
| 2.2.2.2 | 192.168.1.3 |
| 2.2.2.2 | 192.168.1.3 |
The JSON data is below to be given to the value argument parameter of the transformer for the samples.
[
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.3"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.3"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.3"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.3"
}
]
Deduplicate by SourceIP.
keys: SourceIP
Output
It will give you the result below.
It’s guaranteed to keep the original order, and gives you the first record when multiple records are found by collecting keys given.
| DestinationIP | SourceIP |
|---|---|
| 1.1.1.1 | 192.168.1.1 |
| 1.1.1.1 | 192.168.1.2 |
| 1.1.1.1 | 192.168.1.3 |
[
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.3"
}
]
Deduplicate by SourceIP and DestinationIP.
keys: SourceIP, DestinationIP
Output
It will give you the result below.
It’s guaranteed to keep the original order, and gives you the first record when multiple records are found by collecting keys given.
| DestinationIP | SourceIP |
|---|---|
| 1.1.1.1 | 192.168.1.1 |
| 1.1.1.1 | 192.168.1.2 |
| 1.1.1.1 | 192.168.1.3 |
| 2.2.2.2 | 192.168.1.1 |
| 2.2.2.2 | 192.168.1.2 |
| 2.2.2.2 | 192.168.1.3 |
[
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "1.1.1.1",
"SourceIP": "192.168.1.3"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.1"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.2"
},
{
"DestinationIP": "2.2.2.2",
"SourceIP": "192.168.1.3"
}
]
Examples-2
Here is an array to be used as samples in the Examples-2.
It will be given to the value argument parameter of the transformer for the samples.
[
null,
1,
{
"key": "value1"
},
2,
0.5,
0,
0.5,
"aaa",
1,
{
"key": "value1"
},
null,
"aaa",
"ZZZ"
]
Deduplicate an array without keys.
keys:
Output
It will give you the result below.
It’s guaranteed to keep the original order, and gives you the first record when multiple records are found by collecting keys given.
[
null,
1,
{
"key": "value1"
},
2,
0.5,
0,
"aaa",
"ZZZ"
]