0
votes

Comment aplatir une liste contenant à la fois des chaînes et des listes de chaînes?

Quelle est la meilleure façon d'aplatir un ArrayList<Object> qui contient à la fois des ArrayList<Object> ArrayList<String> et String dans un ArrayList<String> plat?

Exemple

Entrée: [item1, item2, item3, [item4a, item4b, item4c]]

Résultat attendu: [item1, item2, item3, item4a, item4b, item4c]

Code pour créer un exemple factice:

|               for (Object s : item) {
for-each not applicable to expression type
  required: array or java.lang.Iterable
  found:    java.lang.Object

Solution (non) fonctionnelle

private ArrayList<String> flattenList(ArrayList<Object> objectList) {
    ArrayList<String> flatLst = new ArrayList<String>();
    
    for (Object item :  objectList) {
        if (item.getClass() == ArrayList.class) {
            System.out.println(item);
            for (Object s : item) {
                flatLst.add(String.valueOf(s));
            }
        } else if (item.getClass() == String.class) {
            flatLst.add(String.valueOf(item));
        }
    }
    return flatLst;
}

Cela donne l'erreur suivante.

ArrayList<Object> objectList = new ArrayList<Object>();
objectList.add("item1");
objectList.add("item2");
objectList.add("item3");

ArrayList<String> subList = new ArrayList<String>();
subList.add("item4a");
subList.add("item4b");
subList.add("item4c");

objectList.add(subList);

Question : comment résoudre ce problème? Ou peut-être mieux, quelle est la meilleure façon de résoudre ce problème?


0 commentaires

4 Réponses :


2
votes

Vous devez aider le compilateur en castant l'élément comme ceci:

private ArrayList<String> flattenList(ArrayList<Object> objectList) {
    return objectList.stream()
            .flatMap(this::extract)
            .collect(Collectors.toCollection(ArrayList::new));

}

private Stream<String> extract(Object item) {
    if (item.getClass() == ArrayList.class) {
        return ((List<String>) item).stream();
    } else if (item.getClass() == String.class) {
        return Stream.of((String) item);
    }
    return Stream.empty();
}

Ou si vous voulez une solution élégante, vous pouvez utiliser des flux comme ceci:

for (Object s : (List) item) {


3 commentaires

Merci! Cependant, j'obtiens la non-static variable this cannot be referenced from a static context erreur qui non-static variable this cannot be referenced from a static context


Que vouliez-vous dire @Andy? Quelle solution cause ce problème?


Je ne sais pas trop quel était le problème exact ici, lorsque j'essayais de compiler, j'obtenais l'erreur ci-dessus. Merci de votre aide! J'ai récompensé @Abra pour sa concision



1
votes

Les boucles for-each nécessitent des tableaux ou une instance de Iterable comme opérande de droite. Le type d' item est Object , vous devez donc d'abord le lancer.

if (item.getClass() == ArrayList.class) {
        ArrayList list = (ArrayList) item;
        for (Object s : list) {
            flatLst.add(String.valueOf(s));
        }
    }


0 commentaires

1
votes

Utilisation de l' API de flux

List<String> flat = objectList.stream()
                              .map(obj -> (obj instanceof List) ? (List<Object>) obj : List.of(obj))
                              .flatMap(list -> list.stream())
                              .map(obj -> String.valueOf(obj))
                              .collect(Collectors.toList());

Au-dessus du code imprime ...

[item1, item2, item3, item4a, item4b, item4c]

ÉDITER

Comme demandé. List<String> au lieu de List<Object>

ArrayList<Object> objectList = new ArrayList<Object>();
objectList.add("item1");
objectList.add("item2");
objectList.add("item3");

ArrayList<String> subList = new ArrayList<String>();
subList.add("item4a");
subList.add("item4b");
subList.add("item4c");

objectList.add(subList);
List<Object> flat = objectList.stream()
                              .map(obj -> (obj instanceof List) ? (List<Object>) obj : List.of(obj))
                              .flatMap(list -> list.stream())
                              .collect(Collectors.toList());
System.out.println(flat);


1 commentaires

C'est génial, merci. Comment le faire renvoyer une List<String> au lieu de List<Object> ?



1
votes

Voici une autre façon de faire la même chose si vous devez le faire en utilisant loop. Si vous pouvez utiliser java8 que la solution par YCF_L, c'est mieux.

public static ArrayList<String> flattenList(ArrayList<Object> objectList) {
        ArrayList<String> flatLst = new ArrayList<String>();
        
        for (Object item :  objectList) {
            if (item instanceof List) {
                System.out.println(item);
                for (Object s : (List)item) {
                    flatLst.add(String.valueOf(s));
                }
            } else if (item instanceof String ) {
                flatLst.add(String.valueOf(item));
            }
        }
        return flatLst;
    }


0 commentaires