На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Следующие правила действуют в данном разделе в дополнение к общим Правилам Форума
1. Здесь обсуждается Java, а не JavaScript! Огромная просьба, по вопросам, связанным с JavaScript, SSI и им подобным обращаться в раздел WWW Masters или, на крайний случай, в Многошум.
2. В случае, если у вас возникают сомнения, в каком разделе следует задать свой вопрос, помещайте его в корневую ветку форума Java. В случае необходимости, он будет перемещен модераторами (с сохранением ссылки в корневом разделе).

3. Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.
4. Не рекомендуется создавать несколько несвязанных вопросов в одной теме. Пожалуйста, создавайте по одной теме на вопрос.
Модераторы: dark_barker, wind
  
> Поиск value в Map<String, Object> и последующая замена , Найти в map некое value которое является String и удовлетворяет некому условию или регулярному выражению
    Всем привет, кто еще здесь остался :lol: ! Задача в следующем. Есть сложная мапа: Map<String, Object> где Object может быть String, Long, List<Object>, Map<String, Object>. Так вот, в дебрях этой мапы мне надо найти все значения, которые являются String и которые удовлетворяют некому условию, например, регулярному выражению, и произвести замену в строке (заменить часть строки), обновив исходный Map. Уровень вложенности объектов не большой - не более 4 уровней. Как заменить value в Map или List я знаю. Вопрос в том, как найти. Ничего умнее рекурсивного поиска в лоб я не придумал с базовой конструкцией вида:
    ExpandedWrap disabled
      void findInMap(Map<String, Object> map){
              for(Map.Entry<String, Object> entry: map.entrySet()){
                  Object objValue = entry.getValue();
                  if(objValue instanceof String){
                     //определяем, соответствует ли строка условию,
                     //если соответствует, производим замену
                  }else if(objValue instanceof Long){
                     //пропускаем
                  }else if(objValue instanceof List){
                     //ищем в List'е, отдельный метод, но по сути тоже самое что и findInMap
                  }else if(objValue instanceof Map){
                     //ищем в Map
                     findInMap( (Map<String, Object>)objValue );
                  }else{
                     //не понятный объект, кидаем исключение
                  }
              }
      }


    Код получается не сказать что сложный, но не маленький. Может есть более красивое решение? Думал насчет стримов (Stream API), но так и не придумал как их использовать для данной задачи, правда я и не очень хорошо эти стримы понимаю.
      Цитата DRON666 @
      Думал насчет стримов (Stream API)

      Они тут ничем не помогут.

      Цитата DRON666 @
      Код получается не сказать что сложный, но не маленький.

      Да не, вполне небольшой.

      Зачем кидать исключение на непонятный объект? Может его просто пропускать мимо вместе с Long'ами?

      Добавлено
      Ну например:

      ExpandedWrap disabled
        import java.util.List;
        import java.util.Map;
        import java.util.Map.Entry;
        import java.util.TreeMap;
        import java.util.function.UnaryOperator;
        import java.util.regex.Pattern;
         
        import static java.util.stream.Collectors.toList;
        import static java.util.stream.Collectors.toMap;
         
        final class FindInMap {
         
            public static void main(String[] args) {
                final Map<String, Object> map = Map.of(
                        "foo", "bar",
                        "Foo", "Bar",
                        "FOO", "BAZ",
                        "gee", List.of(123, "bar", "BAZ"),
                        "qux", Map.of("foo", "Bar", "gee", 567)
                );
                printSortedMap(map);
                final var pattern = Pattern.compile("([bB])ar");
                final var aaargh = new Updater<>(String.class, s -> pattern.matcher(s).matches()
                        ? s.replace("ar", "AAARGH!!!")
                        : s);
                final var aaarghedMap = aaargh.update(map);
                printSortedMap(aaarghedMap);
            }
         
            private static <K, V> void printSortedMap(Map<K, V> map) {
                System.out.println(new TreeMap<>(map));
            }
         
            static final class Updater<T> {
         
                private final Class<T> cls;
                private final UnaryOperator<T> mapper;
         
                Updater(Class<T> cls, UnaryOperator<T> mapper) {
                    this.cls = cls;
                    this.mapper = mapper;
                }
         
                Map<String, Object> update(Map<String, Object> map) {
                    return map.entrySet().stream()
                            .map(this::update)
                            .collect(toMap(Entry::getKey, Entry::getValue));
                }
         
                List<Object> update(List<Object> list) {
                    return list.stream()
                            .map(this::update)
                            .collect(toList());
                }
         
                Entry<String, Object> update(Entry<String, Object> entry) {
                    return new Pair<>(entry.getKey(), update(entry.getValue()));
                }
         
                Object update(Object o) {
                    if (cls.isAssignableFrom(o.getClass())) {
                        @SuppressWarnings("unchecked")
                        final var value = (T) o;
                        return mapper.apply(value);
                    } else if (o instanceof List) {
                        @SuppressWarnings("unchecked")
                        final var list = (List<Object>) o;
                        return update(list);
                    } else if (o instanceof Map) {
                        @SuppressWarnings("unchecked")
                        final var map = (Map<String, Object>) o;
                        return update(map);
                    } else {
                        return o;
                    }
                }
            }
         
            private static final class Pair<A, B> implements Entry<A, B> {
         
                private final A first;
                private final B second;
         
                private Pair(A first, B second) {
                    this.first = first;
                    this.second = second;
                }
         
                @Override
                public A getKey() {
                    return first;
                }
         
                @Override
                public B getValue() {
                    return second;
                }
         
                @Override
                public B setValue(B value) {
                    throw new UnsupportedOperationException("Immutable object");
                }
            }
        }


      =>

      ExpandedWrap disabled
        {FOO=BAZ, Foo=Bar, foo=bar, gee=[123, bar, BAZ], qux={gee=567, foo=Bar}}
        {FOO=BAZ, Foo=BAAARGH!!!, foo=bAAARGH!!!, gee=[123, bAAARGH!!!, BAZ], qux={gee=567, foo=BAAARGH!!!}}
        Ого, очень интересно. О таком функциональном решении я не думал, углубиться в стримы пришлось, спасибо.
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0,0287 ]   [ 15 queries used ]   [ Generated: 18.04.24, 11:34 GMT ]