将这种递归Python方法翻译成Java的最佳方法是什么?

发布于 2024-08-30 21:49:03 字数 1319 浏览 2 评论 0原文

另一个问题中我提供了一个很好的答案,涉及为中国邮递员问题生成某些集合。

提供的答案是:

def get_pairs(s):
    if not s: yield []
    else:
        i = min(s)
        for j in s - set([i]):
           for r in get_pairs(s - set([i, j])):
               yield [(i, j)] + r

for x in get_pairs(set([1,2,3,4,5,6])):
    print x

这将输出所需的结果:

[(1, 2), (3, 4), (5, 6)]  
[(1, 2), (3, 5), (4, 6)]  
[(1, 2), (3, 6), (4, 5)]  
[(1, 3), (2, 4), (5, 6)]  
[(1, 3), (2, 5), (4, 6)]  
[(1, 3), (2, 6), (4, 5)]  
[(1, 4), (2, 3), (5, 6)]  
[(1, 4), (2, 5), (3, 6)]  
[(1, 4), (2, 6), (3, 5)]  
[(1, 5), (2, 3), (4, 6)]  
[(1, 5), (2, 4), (3, 6)]  
[(1, 5), (2, 6), (3, 4)]  
[(1, 6), (2, 3), (4, 5)]  
[(1, 6), (2, 4), (3, 5)]  
[(1, 6), (2, 5), (3, 4)]  

这确实展示了 Python 的表达能力,因为这几乎正是我为算法编写伪代码的方式。我特别喜欢yield 的使用以及集合被视为一等公民的方式。

然而,这就是我的问题。

最好的方法是什么:

1. 在 Java 中复制yield return 构造的功能?最好维护一个列表并将我的部分结果附加到该列表中吗?你会如何处理yield关键字。

2.处理集合的处理?我知道我可能可以使用实现 Set 接口的 Java 集合之一,然后使用诸如 removeAll() 之类的东西来给我一个集合差异。在这种情况下你会这么做吗?

最终,我希望在 Java 中将该方法简化为尽可能简洁和直接的方式。我认为该方法的 java 版本的返回类型可能会返回 int 数组列表或类似的内容。

当将此方法转换为 Java 时,您将如何处理上述情况?

In another question I was provided with a great answer involving generating certain sets for the Chinese Postman Problem.

The answer provided was:

def get_pairs(s):
    if not s: yield []
    else:
        i = min(s)
        for j in s - set([i]):
           for r in get_pairs(s - set([i, j])):
               yield [(i, j)] + r

for x in get_pairs(set([1,2,3,4,5,6])):
    print x

This will output the desire result of:

[(1, 2), (3, 4), (5, 6)]  
[(1, 2), (3, 5), (4, 6)]  
[(1, 2), (3, 6), (4, 5)]  
[(1, 3), (2, 4), (5, 6)]  
[(1, 3), (2, 5), (4, 6)]  
[(1, 3), (2, 6), (4, 5)]  
[(1, 4), (2, 3), (5, 6)]  
[(1, 4), (2, 5), (3, 6)]  
[(1, 4), (2, 6), (3, 5)]  
[(1, 5), (2, 3), (4, 6)]  
[(1, 5), (2, 4), (3, 6)]  
[(1, 5), (2, 6), (3, 4)]  
[(1, 6), (2, 3), (4, 5)]  
[(1, 6), (2, 4), (3, 5)]  
[(1, 6), (2, 5), (3, 4)]  

This really shows off the expressiveness of Python because this is almost exactly how I would write the pseudo-code for the algorithm. I especially like the usage of yield and and the way that sets are treated as first class citizens.

However, there in lies my problem.

What would be the best way to:

1.Duplicate the functionality of the yield return construct in Java? Would it instead be best to maintain a list and append my partial results to this list? How would you handle the yield keyword.

2.Handle the dealing with the sets? I know that I could probably use one of the Java collections which implements that implements the Set interface and then using things like removeAll() to give me a set difference. Is this what you would do in that case?

Ultimately, I'm looking to reduce this method into as concise and straightforward way as possible in Java. I'm thinking the return type of the java version of this method will likely return a list of int arrays or something similar.

How would you handle the situations above when converting this method into Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自找没趣 2024-09-06 21:49:03

为了将生成器函数转换为 Java,您必须将其重新实现为 Iterable+Iterator。例如:

def foo(x):
   for i in xrange(10):
      yield x * i
...
for x in foo(5):
   print(x)

成为(警告:代码未经测试):

import java.util.Iterator;
import java.util.Iterable;

class Foo implements Iterable<Integer> {
   public final int x;

   public Foo(int x) {
      this.x = x;
   }

   public Iterator<Integer> iterate() {
      return new Iterator<Integer> {
         int i = 0;

         public boolean hasNext() {
            return i < 10;
         }

         public Integer next() {
            return x * (i ++);
         }
      };
   }
}
...
for (int x : new Foo(5)) {
   System.out.println(x);
}

对于集合,我确实会使用java.util.HashSet

In order to translate a generator function to Java you have to reimplement it as a Iterable+Iterator. E.g.:

def foo(x):
   for i in xrange(10):
      yield x * i
...
for x in foo(5):
   print(x)

Becomes (warning: code is not tested):

import java.util.Iterator;
import java.util.Iterable;

class Foo implements Iterable<Integer> {
   public final int x;

   public Foo(int x) {
      this.x = x;
   }

   public Iterator<Integer> iterate() {
      return new Iterator<Integer> {
         int i = 0;

         public boolean hasNext() {
            return i < 10;
         }

         public Integer next() {
            return x * (i ++);
         }
      };
   }
}
...
for (int x : new Foo(5)) {
   System.out.println(x);
}

For the sets I would indeed use java.util.HashSet.

反目相谮 2024-09-06 21:49:03

您可能想在 JVM 上运行它。为什么不使用 Scala?

我认为你可以将python代码翻译成scala中几乎相同的代码。比冗长的 java 东西好多了。最终它是 jvm 字节码,可以轻松地与您的 java 应用程序混合/协作。

You probably want to run it on a JVM. Why not use Scala?

I think you can translate the python code into almost the same kind of code in scala. Much better then the verbose java stuff. And it's jvm bytecode in the end which will easily blend in/cooperate with your java app.

计㈡愣 2024-09-06 21:49:03

这不是你所要求的,但我想尝试一下,所以这里有一个使用 LINQ 的 C# 解决方案:

static IEnumerable<IEnumerable<int>> getPairs(IEnumerable<int> list)
{
    if (!list.Any())
        return new [] { new int[0] };

    var first = list.First();
    return from second in list.Skip(1)
           from pair in getPairs(list.Skip(1).Where(rest => rest != second))
           select Enumerable.Concat(new [] { first, second }, pair);
}

实际上并不返回对,只是有序的整数列表,但是在这之后将其切成两半很容易。另外,很高兴看到 C# 可以与 Python 的简洁性相媲美。
测试一下:

foreach (var p in getPairs(new [] { 1, 2, 3, 4, 5, 6 }))
    Console.WriteLine("[" + 
        String.Join(",", p.Select(i => i.ToString()).ToArray()) + "]");

输出:

[1,2,3,4,5,6]
[1,2,3,5,4,6]
[1,2,3,6,4,5]
[1,3,2,4,5,6]
[1,3,2,5,4,6]
[1,3,2,6,4,5]
[1,4,2,3,5,6]
[1,4,2,5,3,6]
[1,4,2,6,3,5]
[1,5,2,3,4,6]
[1,5,2,4,3,6]
[1,5,2,6,3,4]
[1,6,2,3,4,5]
[1,6,2,4,3,5]
[1,6,2,5,3,4]

归功于 Noldorin 对另一个问题的回答 LINQ 问题的一些想法。

This isn't what you asked for, but I wanted to try it out, so here's a solution in C# using LINQ:

static IEnumerable<IEnumerable<int>> getPairs(IEnumerable<int> list)
{
    if (!list.Any())
        return new [] { new int[0] };

    var first = list.First();
    return from second in list.Skip(1)
           from pair in getPairs(list.Skip(1).Where(rest => rest != second))
           select Enumerable.Concat(new [] { first, second }, pair);
}

Doesn't actually return pairs, just ordered lists of integers, but chopping it up by twos after this is easy. Also, nice to see that C# can rival the conciseness of Python.
Testing it out:

foreach (var p in getPairs(new [] { 1, 2, 3, 4, 5, 6 }))
    Console.WriteLine("[" + 
        String.Join(",", p.Select(i => i.ToString()).ToArray()) + "]");

And the output:

[1,2,3,4,5,6]
[1,2,3,5,4,6]
[1,2,3,6,4,5]
[1,3,2,4,5,6]
[1,3,2,5,4,6]
[1,3,2,6,4,5]
[1,4,2,3,5,6]
[1,4,2,5,3,6]
[1,4,2,6,3,5]
[1,5,2,3,4,6]
[1,5,2,4,3,6]
[1,5,2,6,3,4]
[1,6,2,3,4,5]
[1,6,2,4,3,5]
[1,6,2,5,3,4]

Credit to Noldorin's answer to another LINQ question for some ideas.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文