从列表中定义对的算法

时间:2016-11-26 14:24:14

标签: algorithm scala language-agnostic hlist

圣诞节即将到来:是时候确定谁将向谁赠送礼物。我正在寻找这样的算法。

以列表(1 to 10)为例,创建随机对,确保:

  • 每个人的项目都与另一个项目相关联;
  • 没有任何项目与自身相关;
  • 每个项目只关联一次。

很明显,简单的洗牌是不够的:

Random.shuffle(1 to 10)
  .toSeq
  .zipWithIndex

例如:

1 -> 2
2 -> 4
3 -> 1
4 -> 3

但不是(1向自己赠送礼物):

1 -> 1
2 -> 3
3 -> 4
4 -> 2

我一直在考虑对HList进行约束,但是:

  • 我无法表达
  • 这可能有点矫枉过正(即使它很有趣)
  • 可能有算法确保“按构造”

4 个答案:

答案 0 :(得分:2)

万无一失的解决方案:随机为名称分配索引;选择一个随机素数N(如果这个数字本身是一个素数,则除了人数之外)并在索引列表中应用一个轮换N个位置(以人数为模)。

Java代码(任何java代码都是scala代码,对吧?)

ArrayList<String> names=
    new ArrayList<>(Arrays.asList("Ann","Bob","Ed","Kim","Sue","Tom"));
SecureRandom rng=new SecureRandom(); // better seed it
String rndNames[]=new String[names.size()];
for(int i=0; names.size()>0; i++) {
  int removeAt=rng.nextInt(names.size());
  rndNames[i]=names.remove(removeAt);
}
int offset=1; // replace this with a random choice of a 
              // number coprime with rndNames.length, followed by
              // offset = (randomPrime % rndNames.length)
              // 1 will do just fine for the offset, it is a valid value anyway
for(int i=0; i<rndNames.length; i++) {
   System.out.println(rndNames[i] +"->"+rndNames[(i+offset) % rndNames.length]);
}    

结果:

Ann->Sue
Sue->Bob
Bob->Ed
Ed->Tom
Tom->Kim
Kim->Ann

答案 1 :(得分:1)

只是一个模拟示例: 有几种情况需要考虑:

import scala.collection.mutable.ListBuffer
import scala.util.Random

val n = 5
val rnd = new Random()
val result = ListBuffer.fill(n)( (0, 0) )

我确信这可以优化。

while( result.exists(x => x._1 == 0 && x._2 == 0) == true){
  val idx = result.zipWithIndex
  val p = idx.find(x => x._1._1 == 0 && x._1._2 == 0)
  p match {
    case None => Unit// ???
    case Some(x) => {
      val r = rnd.nextInt(n)
      if (result.exists(r => r._2 == r && x._2 != r) == false)
        result(x._2) = (x._2 + 1, r + 1)
    }
  }
}


result.foreach(x => println(x._1 + " : " + x._2 ))

答案 2 :(得分:1)

使用 - src (contains only subdirectories) - Entity (contains the entity files) - Repositories - App (empty) 将确保没有重复项,并且由于Set没有已定义的顺序,因此迭代它将会随机显示。

Set

然后进行循环协会。

val names = Set("Ann","Bob","Ed","Kim","Sue","Tom") // alphabetical

答案 3 :(得分:0)

实际上,这个简单的算法应该是技巧。

  1. 随机播放初始列表
  2. 将索引i关联到索引i+1(以列表大小为模)
  3. 这应该是随机的,以满足需要。

    val people = Random.shuffle(Seq("a", "b", "c", "d"))
    
    val associationIndices = (0 to people.length-1)
      .map(left => (left, (left + 1) % people.length))
      .foreach(assoc => println(s"${people(assoc._1)} -> ${people(assoc._2)}"))
    

    结果是:

    c -> d
    d -> a
    a -> b
    b -> c
    

    只要列表至少包含2个元素,它就会起作用。