Как ни странно, итерировать группы совсем не обязательно!
1) группа у вас состоит из одного элемента. В вашем примере F и X - две группы, в которые нужно положить номера строк.
2) за один проход бежим по строкам и добавляем их в соответствующие группы термов, которые держим в hashtable, где ключом у нас сам терм, а значением - массив из номеров строк.
3) после того, как заполнили хеш, пробегаемся по нему один раз и смотрим, у кого длина массива больше единицы, это и будут исходные группы.
Если нам нужно дополнительно сформировать группы из двух-трех термов, то делает все тоже самое, но ключом ставим treeset из этих элементов.
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeSet;
public class Groups {
public static void main(String[] args) {
String[] myData = {
"F;I;J",
"F;X;A",
"X;D;P",
"A;B;C",
"X;Y;Z",
"J;A;Z",
"U;V;W",
"E;E;E",
"D;F;G",
};
HashMap<String, TreeSet<Integer>> groups = new HashMap<String, TreeSet<Integer>>();
for(int line=0; line< myData.length; line++ ) { // бежим по строкам
List<String> terms = Arrays.asList(myData[line].split(";")); // разбиваем на термы
for(String term: terms) { // пробегаем по термам
TreeSet<Integer> group = groups.get(term); // выдергиваем группу
if(group == null) { // если группы нет
group = new TreeSet<Integer>();
groups.put(term, group);
}
group.add(line); // добваляем строку
}
}
// выводим результат
for(Entry<String, TreeSet<Integer>> group: groups.entrySet()) {
if(group.getValue().size() >1)
System.out.printf("%s - %s\n", group.getKey().toString(), group.getValue().toString());
}
}
}
И результат
A - [1, 3, 5]
D - [2, 8]
F - [0, 1, 8]
J - [0, 5]
X - [1, 2, 4]
Z - [4, 5]