# Tips on performing cross() between values that aren’t perfectly equal?

**URL:** <https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322>\
**Category:** Support and Helpdesk\
**Created:** [May 22, 2025, 3:25pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322 "2025-05-22T15:25:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![archilecteur](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/archilecteur/32/1099_2.png) [@archilecteur](https://forum.openrefine.org/u/archilecteur)\
**Post date:** [May 22, 2025, 3:25pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/1 "2025-05-22T15:25:27Z")

</div>

Hello OR Community,

I have a list of published conference titles, on one hand, and a list of preliminary conference titles (as submitted to the conference organizers prior to selection), together with their abstracts, on the other hand. I have to cross-reference the data so as to associate the abstracts submitted at the time of evaluation with the titles of the conferences that were actually included in the congress program. (The abstracts were not published in the final program).

However, titles are sometimes changed along the way, or more simply, slight differences are introduced to facilitate indexing when the program is published. If I have to resort to losing abstracts whose titles have been completely reworked, I’d like to catch the ones that are similar. Ideally, I’d need a bit more robust solution than using fingerprint().

While I’m thinking about it, a function for antidictionary() would also be nice. (With help, I managed to build one in Google Sheets a few years ago).

Should a Samaritan revive Yatszhash [FuzzyMatch extension](https://github.com/yatszhash/refine-fuzzymatch-extension)?

---

<div class="post-metadata">

**Author:** ![b2m](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/b2m/32/139_2.png) [@b2m](https://forum.openrefine.org/u/b2m)\
**Post date:** [May 23, 2025, 7:40am UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/2 "2025-05-23T07:40:40Z")

</div>

Here are some other ideas and/or strategies to handle this situation ordered from easy to more complex:

1. You could create a "key" column from the titles in each of your projects e.g. by using [fingerprint](https://openrefine.org/docs/manual/grelfunctions#fingerprints) or other GREL functions and then use the "key" columns for `cross`. But as you already stated "fingerprint" might not be enough.
2. You could use [csv-reconcile](https://github.com/gitonthescene/csv-reconcile) and use the more fuzzy and user friendly reconciling process in OpenRefine.
3. You could load both projects into one and use the new [custom clustering methods](https://openrefine.org/docs/manual/cellediting#custom-clustering-methods) to identify the matching titles.
4. You could write your own matching functions/algorithms and call them via [Jython](https://openrefine.org/docs/manual/jythonclojure#jython).

The strategy of course also depends on whether you are able to write and or run Python scripts in your environment.

---

<div class="post-metadata">

**Author:** ![thadguidry](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/thadguidry/32/653_2.png) [@thadguidry](https://forum.openrefine.org/u/thadguidry)\
**Post date:** [May 23, 2025, 12:33pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/3 "2025-05-23T12:33:30Z")

</div>

String Similarity is the problem domain in this case. Almost all of those functions are available in Clustering. Outside of OoenRefine, there are many other tools that might perform better for the fuzzy lookup or fuzzy record linkage that you are specifically needing. To start, take a look at Fuzzy Lookup Add-in for Excel [https://www.microsoft.com/en-us/download/details.aspx?id=15011](https://www.microsoft.com/en-us/download/details.aspx?id=15011)

---

<div class="post-metadata">

**Author:** ![archilecteur](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/archilecteur/32/1099_2.png) [@archilecteur](https://forum.openrefine.org/u/archilecteur)\
**Post date:** [May 23, 2025, 1:57pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/4 "2025-05-23T13:57:07Z")

</div>

Thanks Benjamin and Thad for the answers.

Ideally, I'd like to invoke the more advanced clustering algorithms when running cross(). Loading both datasets in the same project might be feasible in this case, and work with a combination of clustering runs and some custom manipulations.

Nevertheless, I'll probably have to go the reconciliation route at some point, as I have a few more cases of similar tasks to complete this summer, and it's piling up.

Is there a more concise way to use stopwords in GREL than: word, (word != "le").and(word != "les").and(word != "la").and...)?

---

<div class="post-metadata">

**Author:** ![b2m](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/b2m/32/139_2.png) [@b2m](https://forum.openrefine.org/u/b2m)\
**Post date:** [May 24, 2025, 4:01pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/5 "2025-05-24T16:01:49Z")

</div>

> [@archilecteur](#):
>
> Is there a more concise way to use stopwords in GREL than: word, (word != "le").and(word != "les").and(word != "la").and...)?

How about using [inArray](https://openrefine.org/docs/manual/grelfunctions#inarraya-s) for that.

```javascript
["le", "les", "la"].inArray("needle")

```

---

<div class="post-metadata">

**Author:** ![archilecteur](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/archilecteur/32/1099_2.png) [@archilecteur](https://forum.openrefine.org/u/archilecteur)\
**Post date:** [May 26, 2025, 3:29pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/6 "2025-05-26T15:29:50Z")

</div>

Hi @b2m,

Not sure how to integrate inArray to accomplish what I’m looking for (in a custom clustering, add to a transformation of the type **fingerprint** the exclusion of a list of words). [As is done here](https://openrefine.org/docs/manual/cellediting#custom-clustering-methods), but more concisely, in the case of a (much) longer list.

Since Friday I did read about [this Jython solution](https://github.com/OpenRefine/OpenRefine/wiki/Recipes#removeextract-words-contained-in-a-file), and I might take that route.

But still curious about the articulation of **inArray** with custom clustering, if it’s doable.

In any case, thank you for the replies!

---

<div class="post-metadata">

**Author:** ![b2m](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/b2m/32/139_2.png) [@b2m](https://forum.openrefine.org/u/b2m)\
**Post date:** [May 27, 2025, 6:14am UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/7 "2025-05-27T06:14:33Z")

</div>

I guess it is easier to first apply `fingerprint` and then perform the filtering of your stopwords.

In GREL this looks like:

```javascript
filter(
    fingerprint(value).split(" "),
    v,
    not(["le", "les", "la"].inArray(v))
).join(" ")

```

But when you have really big stopword lists, then using Jython to load them from a file on disk is also feasible.

---

<div class="post-metadata">

**Author:** ![archilecteur](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.openrefine.org/archilecteur/32/1099_2.png) [@archilecteur](https://forum.openrefine.org/u/archilecteur)\
**Post date:** [May 27, 2025, 7:29pm UTC](https://forum.openrefine.org/t/tips-on-performing-cross-between-values-that-aren-t-perfectly-equal/2322/8 "2025-05-27T19:29:13Z")

</div>

Actually an elegant solution there. For a short list of stopwords anyway.

Thank you Benjamin!
