简体   繁体   中英

How do I clean up a complicated .map function?

Introduction:

I am trying to get my head around how to update deeply nested data using Equatable and .copyWith methods and in doing so, I have made a complex .map function.

Problem:

Ideally, I would like to use some iterative functional programming technique to simplify the getNewHierarchy() function; but the solution eludes me. The minimal code works as expected, and I can update the deeply nested data in my code. But, it has to lead to a complex .map function (labelled in the minimum viable code '//TODO: I would like to clean this method and make it less complex.'). Try as I might, I cannot find a way to reduce the complexity of this function using a composite design pattern or another functional programming technique without breaking it.

Objective:

This is a remake of a project that I am working on that has a bigger purpose than the question. It is the most basic of minimal viable code for the questions. In the main method, I patch together a deeply nested data object, and then I can 'getNewHierarchy()' to rename the nested object of choice. In this case, I have randomly inserted an object of the nested class for example purposes only. The objective is to make the getNewHierarchy() function less complex without breaking my code. This method maps through the NestedClass object looking for the object of a class and changes it's name. If it does not find the object, it goes into the list of children looking for the class and changes its name when it finds the correct object. This code is very messy.

Question:

How can I simplify the complex .map function that works with deeply nested data?

My code:

// add equatable: ^2.0.5 to pubspec.yaml

import 'package:equatable/equatable.dart';

void main() {
  /// Minimum viable code to reproduce the issue
  var greatGrandParents =
      const NestedClass(name: 'Great Grand Parents', children: [
    NestedClass(name: ' Grand Parents 1', children: [
      NestedClass(name: '  Parents 1', children: [
        NestedClass(name: '   Children 1', children: []),
        NestedClass(name: '   Children 2', children: []),
      ]),
      NestedClass(name: '  Parents 2', children: [
        NestedClass(name: '   Children 3', children: []),
        NestedClass(name: '   Children 4', children: []),
      ]),
      NestedClass(name: '  Parents 3', children: [
        NestedClass(name: '   Children 5', children: []),
        NestedClass(name: '   Children 6', children: []),
      ])
    ]),
    NestedClass(name: ' Grand Parents 2', children: [])
  ]);

  print('=====================');
  print('Original: ');
  greatGrandParents.printChildrenNames();

  print('=====================');
  print('Updated: ');
  final childToBeUpdated = greatGrandParents.children[0].children[1];
  final updatedHierarchy =
      getNewHierarchy('***George***', childToBeUpdated, greatGrandParents);
  updatedHierarchy.printChildrenNames();

  print('=====================');
}

// Model
    class NestedClass extends Equatable {
  final String name;
  final List<NestedClass> children;
  const NestedClass({
    required this.name,
    required this.children,
  });

  printChildrenNames() {
    print(name);
    for (var child in children) {
      child.printChildrenNames();
    }
  }

  NestedClass copyWith({
    String? name,
    List<NestedClass>? children,
  }) {
    return NestedClass(
      name: name ?? this.name,
      children: children ?? this.children,
    );
  }

  @override
  List<Object> get props => [name, children];
}

//TODO: I would like to clean this method and make it less complex.
NestedClass getNewHierarchy(
    String newName, NestedClass person, NestedClass old) {
  NestedClass copiedPerson = person.copyWith(
    children: old.children
        .map((e) => e.copyWith(
              name: e == person ? newName : e.name,
              children: e.children
                  .map((e) => e.copyWith(
                        name: e == person ? newName : e.name,
                        children: e.children
                            .map(
                              (e) =>
                                  e == person ? e.copyWith(name: newName) : e,
                            )
                            .toList(),
                      ))
                  .toList(),
            ))
        .toList(),
  );
  return copiedPerson;
}

Appreciate if someone can advise. Thank you in advance!

Yikes, this would be much easier to solve if you, at all, ever, explained what the heck the getNewHierarchy function is supposed to do.

From what I can tell, you pass it a new name, an old version and a new version, then proceed to replace the new version's children with the old version's, but before doing that, you check each of the children against the new class and if they match, you change their name, and if they don't you keep it?

How about something like this?

NestedClass getNewHierarchy(String newName, NestedClass newValue, NestedClass oldValue) {
  return newValue.copyWith(
    name: oldValue == newValue ? newName : oldValue.name,
    children: oldValue.children.map((v) => getNewHierarchy(newName, v, newValue)).toList(),
  );
}

Also from what I can tell, your data is never equal? Is that just cuz this is an example? You already know you want to edit the greatGrandParents.children[0].children[1]; child, so why don't you update it directly???

Also if you are gonna change both the name and children, you know, the two only things in your class, there is no use for a copyWith call, you can just use a normal constructor:

return NestedClass(
    name: oldValue == newValue ? newName : oldValue.name,
    children: oldValue.children.map((v) => getNewHierarchy(newName, v, newValue)).toList(),
  );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM