0

一意の数字を持つすべての N 桁の長い数字のリストを作成しようとしていますが、より大きな問題の一部としてそれを一般化する方法がわかりません。 ) 一意の数字を持つ数字の長い数字。

n = 4 の手書きコードは次のとおりです。

for {
  x1 <- 1 to 9
  x2 <- 1 to 9
  x3 <- 1 to 9
  x4 <- 1 to 9
  if (x1 != x2 && x2 != x3 && x3 != x4 && x1 != x3 && x1 != x4 && x2 != x4)
  num4 = x1 + x2 * 10 + x3 * 100 + x4 * 1000
} yield num4
4

3 に答える 3

8
scala> "1234".combinations(2).toList
res9: List[String] = List(12, 13, 14, 23, 24, 34)

範囲付き:

scala> (1 to 9).combinations(4).toList
res12: List[scala.collection.immutable.IndexedSeq[Int]] = List(Vector(1, 2, 3, 4), Vector(1, 2, 3, 5), Vector(1, 2, 3, 6), Vector(1, 2, 3, 7), Vector(1, 2, 3, 8), Vector(1, 2, 3, 9), Vector(1, 2, 4, 5), Vector(1, 2, 4, 6), Vector(1, 2, 4, 7), Vector(1, 2, 4, 8), Vector(1, 2, 4, 9), Vector(1, 2, 5, 6), Vector(1, 2, 5, 7), Vector(1, 2, 5, 8), Vector(1, 2, 5, 9), Vector(1, 2, 6, 7), Vector(1, 2, 6, 8), Vector(1, 2, 6, 9), Vector(1, 2, 7, 8), Vector(1, 2, 7, 9), Vector(1, 2, 8, 9), Vector(1, 3, 4, 5), Vector(1, 3, 4, 6), Vector(1, 3, 4, 7), Vector(1, 3, 4, 8), Vector(1, 3, 4, 9), Vector(1, 3, 5, 6), Vector(1, 3, 5, 7), Vector(1, 3, 5, 8), Vector(1, 3, 5, 9), Vector(1, 3, 6, 7), Vector(1, 3, 6, 8), Vector(1, 3, 6, 9), Vector(1, 3, 7, 8), Vector(1, 3, 7, 9), Vector(1, 3, 8, 9), Vector(1, 4, 5...

Int のリストとして:

 "123456789".combinations(4).map(_.toInt).toList
 res37: List[Int] = List(1234, 1235, 1236, 1237, 1238, 1239, 1245, 1246, 1247, 1248, 1249, 1256, 1257, 1258, 1259, 1267, 1268, 1269, 1278, 1279, 1289, 1345, 1346, 1347, 1348, 1349, 1356, 1357, 1358, 1359, 1367, 1368, 1369, 1378, 1379, 1389, 1456, 1457, 1458, 1459, 1467, 1468, 1469, 1478, 1479, 1489, 1567, 1568, 1569, 1578, 1579, 1589, 1678, 1679, 1689, 1789, 2345, 2346, 2347, 2348, 2349, 2356, 2357, 2358, 2359, 2367, 2368, 2369, 2378, 2379, 2389, 2456, 2457, 2458, 2459, 2467, 2468, 2469, 2478, 2479, 2489, 2567, 2568, 2569, 2578, 2579, 2589, 2678, 2679, 2689, 2789, 3456, 3457, 3458, 3459, 3467, 3468, 3469, 3478, 3479, 3489, 3567, 3568, 3569, 3578, 3579, 3589, 3678, 3679, 3689, 3789, 4567, 4568, 4569, 4578, 4579, 4589, 4678, 4679, 4689, 4789, 5678, 5679, 5689, 5789, 6789)

そして、実際にさまざまな順列に興味がある場合(上記の回答を書いてから質問が少し変わりました)

scala> "1234".combinations(2).toList.flatMap(_.permutations).map(_.toInt)
res51: List[Int] = List(12, 21, 13, 31, 14, 41, 23, 32, 24, 42, 34, 43)
于 2013-07-01T20:39:31.297 に答える
1

あなたが探しているのは、モナディックシーケンスと呼ばれます。forのような理解を使用するとき

for(x <- Set(...)
    y <- Set(...))
  yield (x, y)

(Set(...), Set(...))モナド計算のペアを持ち、結果のペアを保持するモナドに変換すると見ることができますSet((...,...), (...,...), ...)

これは、任意の長さのシーケンスに一般化できます。scalazライブラリは、そのような操作を定義できるシーケンスを表す traitをTraversable定義します。これtraverseはより一般的な操作であり、モナド シーケンスを定義するために使用できます。

import scalaz._
import scalaz.Scalaz._
import scala.collection.immutable._

def sequence[M[_]: Applicative, T[_], A](seq: T[M[A]])
        (implicit t: Traverse[T]): M[T[A]] =
  t.traverse(identity[M[A]], seq);

私たちの場合、MwillSetTwill beSeqです。したがって、 type の一連の選択肢 (セットとして表される) が与えられると、Seq[Set[Int]]選択肢から選択されたすべての可能な組み合わせのセットであるsequenceことがわかります。Set[Seq[Int]]

// a helper function
def set[A](seq: Seq[A]): Set[A] = Set(seq : _*);

// prints all sequences where the first number is from 1 to 9
// and the second number from 2 to 9:
println( sequence(List(set(1 to 9), set(2 to 9))) )

その後、いくつかの数字が複数回出現するシーケンスをフィルタリングできます。

この種のフィルタリングをプロセスに含めたい場合は、さらに複雑になります。モナド計算中は、使用可能な数値を保持する状態を保持する必要があります。定義しましょう

type Choices = Set[Int]
type DigitChoose[A] = StateT[Set,Choices,A]

DigitChoose非決定論的な結果を持つモナドもそうです (以前のように、すべての操作は可能な結果のセットを生成します) が、 type の状態を保持しChoicesます。

次に、コンパイラを少し支援するヘルパー関数をいくつか定義します (一般的な型は多すぎます :))。

// See http://stackoverflow.com/q/7782589/1333025 why we need this:
implicit val applicativeDC: Applicative[DigitChoose]
    = implicitly[Monad[DigitChoose]]

def sequenceDC[A](seq: Seq[DigitChoose[A]]): DigitChoose[Seq[A]]
  = sequence(seq);

これでDigitChoose、シーケンスに対してモナド シーケンスが定義されました。

を使用しDigitChooseて、使用可能な数字の 1 つから数字を選択し、状態を更新する (選択した数字をセットから削除する) 操作を定義できます。

// Pick any of the available digits:
def choose: DigitChoose[Int] =
  stateT((s: Choices) => for(i <- s) yield (s - i, i));

および数字の選択を制限するいくつかの制限されたバリアント:

// Pick an available digit that is also in the given set of choices:
def choose(c: Choices): DigitChoose[Int] =
  stateT((s: Choices) => for(i <- s intersect c ) yield (s - i, i));
// Pick an available digit that is also in the given set of choices:
def choose(cs: Seq[Int]): DigitChoose[Int]
  = choose(cs.toSet);

最後に、次のようなことを行います。

// First digit is unrestricted
// Second digit is from 1 to 3
// Third digit is from 1 to 2
// ... and no digits will be the same!
val choices = Seq(choose, choose(1 to 3), choose(1 to 2));
// Sequence the choices, given that we start with digits 1 to 9
println( sequenceDC(choices) ! Set(1 to 9 : _*) );

完全なコードはgist で入手できます

于 2013-07-02T06:56:46.123 に答える
0

私のアプローチは、興味のない結果を除外することです。
フィルタリングでは、個別の値のみを持つ Set のプロパティを使用します。
n>10 の場合は、n=10 の場合と異なる結果が得られないため、デフォルトに戻すことができます。

def generateUniqueList(n: Int) = {
  val sanitizedInput = if(n>10) 10 else n
  0 to math.pow(10, sanitizedInput).toInt-1 filter(num => num.toString.toSeq.size == num.toString.toSet.size)
}

これは最速の解決策にはなりませんが、その概念は単純で理解しやすいものです。

例:

val result = generateUniqueList(2)
//> result  : scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3, 4,
//|  5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 
//| 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 47, 
//| 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 
//| 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 
//| 90, 91, 92, 93, 94, 95, 96, 97, 98)
于 2013-07-01T20:38:39.200 に答える