我有一个Map< String,String>表示从A到B的链接.我想链接所有可能的路由.例如 :
[A,B]
[B,C]
[C,D]
[E,F]
[F,G]
[H,I]

将输出

[A,B,C,F,I]

我在这里找到了类似的问题(但没有完全满足我的要求):https://stackoverflow.com/a/10176274/298430

这是我的解决方案:

public static <T> Set<List<T>> chainLinks(Map<T,T> map) {
    Set<List<T>> resultSet = new HashSet<>();

    map.forEach((from,to) -> {
      if (!map.containsValue(from)) {
        List<T> list = new ArrayList<>();
        list.add(from);
        list.addAll(inner(to,map));
        resultSet.add(list);
      }
    });
    return resultSet;
  }

  private static <T> List<T> inner(T from,Map<T,T> map) {
    if (map.containsKey(from)) {
      List<T> list = new ArrayList<>();
      list.add(from);
      list.addAll(inner(map.get(from),map));
      return list;
    } else {
      List<T> end = new ArrayList<>();
      end.add(from);
      return end;
    }
  }

和测试用例:

@Test
  public void testChainLinks()  {
    Map<String,String> map = new HashMap<String,String>() {{
      put("A","B");
      put("B","C");
      put("C","D");
      put("E","F");
      put("F","G");
      put("H","I");
    }};

    Utils.chainLinks(map).forEach(list -> {
      logger.info("list = {}",list.stream().collect(Collectors.joining(" -> ")));
    });
  }

它确实正常工作:

list = H -> I
list = E -> F -> G
list = A -> B -> C -> D

但我不喜欢我的解决方案.因为我觉得它可以用更实用的方式解决.我可以在这里感受到stream.fold()的气味.我试过将我的代码转换为纯函数样式但是徒劳无功:这意味着没有中间对象创建…

可能吗 ?任何提示都很感激!

解决方法

使用自定义收集器的替代解决方案具有接近线性的复杂性.它确实比之前提出的解决方案更快,但看起来有点丑陋.
public static <T> Collector<Entry<T,T>,?,List<List<T>>> chaining() {
    BiConsumer<Map<T,arraydeque<T>>,Entry<T,T>> accumulator = (
            m,entry) -> {
        arraydeque<T> k = m.remove(entry.getKey());
        arraydeque<T> v = m.remove(entry.getValue());
        if (k == null && v == null) {
            // new pair does not connect to existing chains
            // create a new chain with two elements
            k = new arraydeque<>();
            k.addLast(entry.getKey());
            k.addLast(entry.getValue());
            m.put(entry.getKey(),k);
            m.put(entry.getValue(),k);
        } else if (k == null) {
            // new pair prepends an existing chain
            v.addFirst(entry.getKey());
            m.put(entry.getKey(),v);
        } else if (v == null) {
            // new pair appends an existing chain
            k.addLast(entry.getValue());
            m.put(entry.getValue(),k);
        } else {
            // new pair connects two existing chains together
            // reuse the first chain and update the tail marker
            // btw if k == v here,then we found a cycle
            k.addAll(v);
            m.put(k.getLast(),k);
        }
    };
    BinaryOperator<Map<T,arraydeque<T>>> combiner = (m1,m2) -> {
        throw new UnsupportedOperationException();
    };
    // our map contains every chain twice: mapped to head and to tail
    // so in finisher we have to leave only half of them 
    // (for example ones connected to the head).
    // The map step can be simplified to Entry::getValue if you fine with
    // List<Collection<T>> result.
    Function<Map<T,List<List<T>>> finisher = m -> m
            .entrySet().stream()
            .filter(e -> e.getValue().getFirst().equals(e.getKey()))
            .map(e -> new ArrayList<>(e.getValue()))
            .collect(Collectors.toList());
    return Collector.of(HashMap::new,accumulator,combiner,finisher);
}

用法:

List<List<String>> res = map.entrySet().stream().collect(chaining());

(我没有实现组合器步骤,因此它不能用于并行流,但它也不是很难添加它).这个想法很简单:我们跟踪到目前为止在地图中找到的部分链,其中键指向链的开始和结束,值是包含到目前为止找到的链的arraydeque对象.每个新条目都会更新现有的deque(如果它附加/预先添加)或将两个deques合并在一起.

根据我的测试,这个版本比带有100个链的50000元件输入阵列的@ saka1029解决方案快1000倍.

java 8链接链接的功能样式的更多相关文章

  1. 吃透移动端 Html5 响应式布局

    这篇文章主要介绍了吃透移动端 Html5 响应式布局,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 如何在iOS上快速将ALAsset映像保存到磁盘?

    我正在使用ALAsset来检索这样的图像:这返回CGImageRef,我想尽快保存到磁盘…解决方案1:解决方案2:问题是两种方法在设备上的执行速度都很慢.每张图片大约需要2秒才能执行此操作.这绝对是长久的.问题:如何加快图像保存过程?或许还有更好的解决方案吗?

  3. ios – 根据大小类更改约束的乘数

    根据当前的大小类,可以给出一个不同乘数的约束吗?我有一个看法,我想要的是一般尺寸类宽度的一半的屏幕尺寸,我希望它是一个紧凑的尺寸类宽度的屏幕尺寸的80%.在故事板中,我可以选择将不同大小的类别的不同变量添加到约束常量值,但不是乘数值.这是相等的宽度限制.我没有在程序上添加约束,所以我希望他们可能是一个解决方案,在这条路上.任何人都可以告诉我是否可以通过故事板或编程方式来做我正在寻找的内容?

  4. 是否可以从我的iOS应用程序包中删除文件?

    解决方法无法删除捆绑包中的文件.必须对应用程序进行签名,如果以任何方式修改了包,它将不会通过签名.我能想到的唯一其他解决方案是设置Web服务,并让您的应用程序根据需要下载部分内容.这可能是也可能不是可行的解决方案,具体取决于您的应用实际执行的操作.

  5. Swift40/90Days - 用函数式编程解决逻辑难题

    Swift90Days-用函数式编程解决逻辑难题这篇翻译的文章,用两种方法解决了同一个逻辑难题。第二种方法利用了Swift的一些语言特性,实现了函数式编程的解决方案。这样的代码对于指令式编程来说再平常不过,接下来我们就来看下如何用函数式编程解决这个问题。Swift中函数已经是一等公民,这让高阶函数变成可能,也就是说,一个函数可以是通过其它函数组装构成的。思考Swift对于函数式编程的支持让我感觉的兴奋,Excited!

  6. Swift 字符串替换/过滤/切割/拼接

    替换为/结果过滤过滤掉单个字符/结果过滤掉开头和结尾的空白结果切割对字符串使用/作为分隔符来切割,不允许空字符串使用split函数结果是一个数组对字符串使用/作为分隔符来切割,允许空字符串结果拼接结果

  7. Swift开发教程--字符串的操作

    替换把?替换为/结果

  8. 关于oc和swift混编 框架framework时 只能在真机运行或只能在模拟器单独运行的解决方案

    问题描述:关于oc和swift混编框架framework时只能在真机运行或只能在模拟器单独运行的解决方案。

  9. swift 网络搜索热词排行

    1.使用www.showapi.com上的接口,需要注册添加一个App,这样才能获取appid和secret密钥,调用前需要订购套餐(选免费的就可以了);2.外部库Podfile文件内容,SnapKit这里暂时不需要用到:3.桥接头文件参考:http://www.jb51.cc/article/p-pcleyxep-te.html4.AppTransportSecurityhasblockedac

  10. tableview 最上面有空白 解决方案

    self.automaticallyAdjustsScrollViewInsets=false

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部