对List <map <string,string =“”>&gt;

时间:2016-07-21 18:57:27

标签: java list sorting comparator

我有一个字符串映射列表:

List<Map<String, String>> list = new ArrayList<Map<String, String>>();

这将填充以下内容:

Map<String, String> action1 = new LinkedHashMap<>();
map.put("name", "CreateFirstName");
map.put("nextAction", "CreateLastName");

Map<String, String> action2 = new LinkedHashMap<>();
map.put("name", "CreateAddress");
map.put("nextAction", "CreateEmail");

Map<String, String> action3 = new LinkedHashMap<>();
map.put("name", "CreateLastName");
map.put("nextAction", "CreateAddress");

Map<String, String> action4 = new LinkedHashMap<>();
map.put("name", "CreateEmail");

list.add(action1);
list.add(action2);
list.add(action3);
list.add(action4);

action4没有nextAction,因为它是最后一个动作,但可能更容易为它提供一个占位符的nextAction,以便不进行下一步操作?

问题:如何对列表进行排序,以便按顺序执行操作? ie:动作的nextAction,与列表中下一个动作的名称相同。

2 个答案:

答案 0 :(得分:1)

不是使用Map来存储操作的属性(namenextAction),而是创建由这些属性组成的自己的类型:

class Action {
    private String name;
    //nextAction

    public void perform() {
        //do current action
        //use nextAction to perform the next action
    }
}

nextAction现在可以作为下一个操作的引用:

abstract class Action implements Action {
    private String name;
    private Action nextAction;

    public Action(String name) {
        this.name = name;
    }

    public final void perform() {
        perform(name);
        nextAction.perform();
    }

    protected abstract void perform(String name);
}

您现在可以通过对Action类进行子类型化来创建操作:

class CreateFirstName extends Action {
    public CreateFirstName(Action nextAction) {
        super("CreateFirstName", nextAction);
    }

    protected final void perform(String name) {
        System.out.println("Performing " + name);
    }
}

将它们连在一起:

Action action = new CreateFirstName(new CreateLastName(new CreateEmail(...)));

嵌套表达式会变得非常混乱,但我们稍后会讨论。这里有一个更大的问题。

  

action4没有nextAction,因为它是最后一个动作,但可能更容易为它提供一个nextForction,它是一个占位符,没有下一个动作

同样的问题适用于上面的代码。

现在,由于构造函数Action(String, Action),每个操作必须有下一个操作。我们可以采用简单的路线并传入一个占位符,无需下一步操作(null是最简单的路线):

class End extends Action {
    public End() {
        super("", null);
    }
}

并进行空检查:

//class Action
public void perform() {
        perform(name);

        if(nextAction != null) {
            nextAction.perform(); //performs next action
        }
    }

但这可能是code smell。你可以在这里停止阅读并使用简单的修复程序,或者在下面继续阅读更多参与(和教育)的路线。

当你使用null时,很可能会成为代码气味的牺牲品。虽然它不适用于所有情况(由于Java的空安全性差),但您应该尝试avoid null if possible。相反,请重新考虑您的设计,如本例所示。如果所有其他方法都失败了,请使用Optional

最后一个动作与其他动作不同。它仍然可以像其他一样执行,但它有不同的属性要求。

这意味着它们可以共享相同的行为抽象,但在定义属性时必须有所不同:

interface Action {
    void perform();
}

abstract class ContinuousAction implements Action {
    private String name;
    private Action nextAction;

    public ContinuousAction(String name) {
        this.name = name;
    }

    public final void perform() {
        perform(name);
        nextAction.perform();
    }

    protected abstract void perform(String name);
}

abstract class PlainAction implements Action {
    private String name;

    public PlainAction(String name) {
        this.name = name;
    }

    public final void perform() {
        perform(name);
    }

    protected abstract void perform(String name);
}

最后一项操作会延长PlainAction,而其他操作会延长ContinuousAction

最后,为了防止长链:

new First(new Second(new Third(new Fourth(new Fifth(new Sixth(new Seventh(new Eighth(new Ninth(new Tenth())))))))))

您可以在每个具体操作中指定下一个操作:

class CreateFirstName extends ContinuousAction {
    public CreateFirstName() {
         super("CreateFirstName", new CreateLastName());
    }

    //...
}

class CreateLastName extends ContinuousAction {
    public CreateLastName() {
        super("CreateLastName", new CreateEmail());
    }

    //...
}

class CreateEmail extends PlainAction {
    public CreateEmail() {
         super("CreateEmail");
    }

    //...
}

可以进一步抽象ContinuousActionPlainAction。它们都是命名的操作(它们具有名称),并且该属性以samw方式影响其contract(将其传递给template method process(String)):< / p>

abstract class NamedAction implements Action {
    private String name;

    public NamedAction(String name) {
        this.name = name;
    }

    public final void perform() {
        perform(name);
    }

    protected abstract void perform(String name);
}

//class ContinuousAction extends NamedAction
//class PlainAction extends NamedAction

答案 1 :(得分:1)

虽然这似乎是XY-Problem的情况,但这个地图列表当然不是一个设计良好的数据模型&#34;,并且可能有一个表示&#34;更好&#34;在很多方面(虽然没有人可以提出关于&#34;最佳&#34;模型的建议,只要总体目标未知),这就是你手边的任务,这就是它的方法可以解决:

首先,您必须确定排序列表的第一个元素。这正是具有"name"条目的地图,该条目不会显示为任何其他地图的"nextAction"条目。

拥有第一张地图后,您可以将其添加到(已排序)列表中。然后,确定下一个元素归结为查找"name"与前一个地图的"nextAction"相同的地图。要快速找到这些后继者,您可以构建一个映射,将每个"name"条目映射到映射本身。

以下是此排序方法的基本实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SortListWithMaps
{
    public static void main(String[] args)
    {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();

        Map<String, String> action1 = new LinkedHashMap<>();
        action1.put("name", "CreateFirstName");
        action1.put("nextAction", "CreateLastName");

        Map<String, String> action2 = new LinkedHashMap<>();
        action2.put("name", "CreateAddress");
        action2.put("nextAction", "CreateEmail");

        Map<String, String> action3 = new LinkedHashMap<>();
        action3.put("name", "CreateLastName");
        action3.put("nextAction", "CreateAddress");

        Map<String, String> action4 = new LinkedHashMap<>();
        action4.put("name", "CreateEmail");

        list.add(action1);
        list.add(action2);
        list.add(action3);
        list.add(action4);        

        // Make it a bit more interesting...
        Collections.shuffle(list);

        System.out.println("Before sorting");
        for (Map<String, String> map : list)
        {
            System.out.println(map);
        }

        List<Map<String, String>> sortedList = sort(list);

        System.out.println("After sorting");
        for (Map<String, String> map : sortedList)
        {
            System.out.println(map);
        }
    }

    private static List<Map<String, String>> sort(
        List<Map<String, String>> list)
    {
        // Compute a map from "name" to the actual map
        Map<String, Map<String, String>> nameToMap = 
            new LinkedHashMap<String, Map<String,String>>();
        for (Map<String, String> map : list)
        {
            String name = map.get("name");
            nameToMap.put(name, map);
        }

        // Determine the first element for the sorted list. For that,
        // create the set of all names, and remove all of them that
        // appear as the "nextAction" of another entry
        Set<String> names = 
            new LinkedHashSet<String>(nameToMap.keySet());
        for (Map<String, String> map : list)
        {
            String nextAction = map.get("nextAction");
            names.remove(nextAction);
        }
        if (names.size() != 1)
        {
            System.out.println("Multiple possible first elements: " + names);
            return null;
        }

        // Insert the elements, in sorted order, into the result list
        List<Map<String, String>> result = 
            new ArrayList<Map<String, String>>();
        String currentName = names.iterator().next();
        while (currentName != null)
        {
            Map<String, String> element = nameToMap.get(currentName);
            result.add(element);
            currentName = element.get("nextAction");
        }
        return result;
    }
}