我正在查看其中一个问题How to merge two sorted arrays,并努力使用Java 8流转换解决方案。但仍然没有成功。实际上,我在这里没有什么用处。
必须有一种方法来使用函数式编程中的索引来处理这样的循环。在不改变时间复杂度的情况下,如何在Scala,Clojure等其他语言中完成这项工作?可能那时我可以尝试用Java复制它。
编辑:代码中提到的问题是最有效的,我不想在此上妥协。
答案 0 :(得分:6)
事实上,到处都有相同的方法:你重复两个集合,将最少的集合头部添加到结果中,然后重复使用其余集合,直到其中一个集合(或两者)为空。在clojure:
(defn merge-sorted [pred coll1 coll2]
(loop [coll1 coll1 coll2 coll2 res []]
(cond (or (empty? coll1) (empty? coll2)) (concat res coll1 coll2)
(pred (first coll1) (first coll2)) (recur (rest coll1)
coll2
(conj res (first coll1)))
:else (recur coll1 (rest coll2) (conj res (first coll2))))))
user> (merge-sorted < [1 3 5 6 7 8 9 40 50] [1 2 5 10 100])
(1 1 2 3 5 5 6 7 8 9 10 40 50 100)
答案 1 :(得分:5)
我认为这很容易用尾递归表达:
def merge(x: List[Int], y: List[Int]): List[Int] = {
def loop(xss: List[Int], yss: List[Int], acc: List[Int]) = (xss, yss) match {
case (x :: xs, y :: ys) if x < y => loop(xs, yss, x :: acc)
case (_, y :: ys) => loop(xss, ys, y :: acc)
case (x :: xs, Nil) => loop(xs, Nil, x :: acc)
case (Nil, Nil) => acc.reverse
}
loop(x, y, Nil)
}
答案 2 :(得分:3)
也许这样的事情?可能做得更漂亮,但总体思路应该有效。
public static <T extends Comparable<T>> Stream<T> foldSorted(Stream<T> left, Stream<T> right) {
Iterator<T> leftIterator = left.iterator();
Iterator<T> rightIterator = right.iterator();
Iterator<T> iterator = new Iterator<T>() {
private T nextLeft = getNextLeft();
private T nextRight = getNextRight();
private T getNextLeft() {
return leftIterator.hasNext() ? leftIterator.next():null;
}
private T getNextRight() {
return rightIterator.hasNext() ? rightIterator.next():null;
}
@Override
public boolean hasNext() {
return nextLeft != null || nextRight != null;
}
@Override
public T next() {
T result = null;
if(nextLeft != null) {
if(nextRight != null) {
if(nextLeft.compareTo(nextRight) < 0) {
result = nextLeft;
nextLeft = getNextLeft();
} else {
result = nextRight;
nextRight = getNextRight();
}
} else {
result = nextLeft;
nextLeft = getNextLeft();
}
} else {
result = nextRight;
nextRight = getNextRight();
}
return result;
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false);
}
现在,你可以这样做:
@Test
public void verifyFoldSorted() {
List<Integer> result = StreamUtils.foldSorted(Stream.of(1, 5, 7, 9), Stream.of(2, 5)).collect(Collectors.toList());
assertEquals(Arrays.asList(1, 2, 5, 5, 7, 9), result);
result = StreamUtils.foldSorted(Stream.of(8, 10), Stream.of(1, 2, 7, 9)).collect(Collectors.toList());
assertEquals(Arrays.asList(1, 2, 7, 8, 9, 10), result);
}
答案 3 :(得分:2)
您可以将要合并的数组包装成二维数组,然后执行:
IntStream result = Arrays.stream(new int[][]{{3, 2, 1}, {5, 2, 4}})
.flatMapToInt(Arrays::stream)
.sorted();
请注意,数组是否已预先排序并不重要。
答案 4 :(得分:2)
<强> Scala的强>
如果你想要一个懒惰的评估,即每个元素只在需要时进行排序和检索,那么一种方法就是将<p ng-repeat="s in mytest.specialities"> {{s.name}} / {{s._id}} / {{s.description}} </p>
转换为Array
s。
Iterator
class ArrayMerger[A:Ordering](arrA:Array[A], arrB:Array[A]) extends Iterator[A] {
import math.Ordering.Implicits._
private val a: BufferedIterator[A] = arrA.toIterator.buffered
private val b: BufferedIterator[A] = arrB.toIterator.buffered
override def hasNext: Boolean = a.hasNext || b.hasNext
override def next(): A =
if (!a.hasNext) b.next()
else if (!b.hasNext) a.next()
else if (a.head < b.head) a.next() else b.next()
}
val am = new ArrayMerger(Array('a','c','t','y'),Array('b','w','z'))//Iterator[Char]
am.toArray // Array(a, b, c, t, w, y, z) <-- iterator consumed
也有惰性评估,但也可以编入索引。
Stream
答案 5 :(得分:2)
@leetwinski的尾递归解决方案效果很好,但它并不懒惰。这是Clojure中的一个懒惰解决方案:
(defn merge-sorted [pred coll1 coll2]
(lazy-seq
(if (some empty? [coll1 coll2])
(concat coll1 coll2)
(let [[head1 & tail1] coll1
[head2 & tail2] coll2]
(if (pred head1 head2)
(cons head1 (merge-sorted pred tail1 coll2))
(cons head2 (merge-sorted pred coll1 tail2)))))))
示例:
(letfn [(multiples [x]
(iterate (partial +' x) x))]
(take 10 (merge-sorted < (multiples 2) (multiples 3))))
;;=> (2 3 4 6 6 8 9 10 12 12)
答案 6 :(得分:0)
您还可以使用折叠在Scala中完成它,
val l1 = List(1,2,3,4)
val l2 = List(1, 2, 3, 4, -1, 2, 3, 5, 6, 7, 8)
val merged = l2.foldLeft(l1)((acc,i) => acc :+ i).sorted
答案 7 :(得分:0)
可以使用第三方库完成:
int[] a = { 1, 3, 5, 7 };
int[] b = { 2, 4, 6 };
int[] c = IntStream.merge(a, b, (v1, v2) -> v1 < v2 ? Nth.FIRST : Nth.SECOND).toArray();
N.println(c); // output: [1, 2, 3, 4, 5, 6, 7]
我无法在此提及图书馆,因为我的帐户可能会因为自我推销而被暂停。但是图书馆可以在我的其他答案中找到。