Python で順列・組み合わせ

itertools を使います。

順列(Permutation)

# -*- coding: UTF-8 -*-
import itertools

for s in itertools.permutations(['A','B','C'], r=3):
    print(s)

重複ありの順列(Repetition Permutation)

for s in itertools.product(['A','B','C'], repeat=3):
    print(s)

組み合わせ(Combination)

for s in itertools.combinations(['A','B','C'], 3):
    print(s)

重複ありの組み合わせ(Homogeneous)

for s in itertools.combinations_with_replacement(['A', 'B', 'C'], 3):
    print(s)

総称型の配列を作るメソッド

配列数が動的な総称型の配列を作る必要がある時、、、

n個の配列、全て null で初期化するなら、

@SuppressWarnings("unchecked")
public static <T> T[] nullArrays(int n, Class<T> cls) {
   return (T[])Array.newInstance(cls, n);
}

ただし、int.class や、char.class を指定できない。

固定の値で初期化するなら、

public static <T> T[] valueArrays(int n, T value) {
   @SuppressWarnings("unchecked")
   T[] t = (T[])Array.newInstance(value.getClass(), n);
   for(int i=0; i < n; i++)  t[i] = value;
   return t;
}

可変引数 T... を使えば、不足分をnull に、、

@SuppressWarnings("unchecked")
public static <T> T[] valueArrays(int n, T...values) {
   T[] t = (T[])Array.newInstance(values[0].getClass(), n);
   int vlen = values.length;
   for(int i=0; i < n; i++)
      t[i] = i < vlen ? values[i] : null;
   return t;
}

例)

String[] sary = valueArrays(5, "A", "B", "C");
String res2 = Arrays.stream(sary).map(e->"["+e+"]").collect(Collectors.joining(""));
System.out.println(res2);

結果

[A][B][C][null][null]

リストから、固定の長さで並びを保持したリストのリストを求める。

リストと連続させる数を指定して、List の List で結果を求める。

public static <T> List<List<T>> lengthSequencelist(List<T> list, int length){
   int last = list.size() - length + 1;
   return Stream.concat(
      IntStream.range(0, last).boxed().map(i->list.subList(i, i + length))
      , IntStream.range(last, list.size()).boxed().map(i->list.subList(i, list.size()))
   ).collect(Collectors.toList());
}

"A"~"Z" のリスト

List<String> list = Arrays.asList("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");

連続7個の組みで、リストを作成

lengthSequencelist(list, 7).stream().forEach(System.out::println);

結果

[A, B, C, D, E, F, G]
[B, C, D, E, F, G, H]
[C, D, E, F, G, H, I]
[D, E, F, G, H, I, J]
[E, F, G, H, I, J, K]
[F, G, H, I, J, K, L]
[G, H, I, J, K, L, M]
[H, I, J, K, L, M, N]
[I, J, K, L, M, N, O]
[J, K, L, M, N, O, P]
[K, L, M, N, O, P, Q]
[L, M, N, O, P, Q, R]
[M, N, O, P, Q, R, S]
[N, O, P, Q, R, S, T]
[O, P, Q, R, S, T, U]
[P, Q, R, S, T, U, V]
[Q, R, S, T, U, V, W]
[R, S, T, U, V, W, X]
[S, T, U, V, W, X, Y]
[T, U, V, W, X, Y, Z]
[U, V, W, X, Y, Z]
[V, W, X, Y, Z]
[W, X, Y, Z]
[X, Y, Z]
[Y, Z]
[Z]

Stream<List<T>> を求める場合、

public static <T> Stream<List<T>> lengthSequenceStream(List<T> list, int length){
   int last = list.size() - length + 1;
   return Stream.concat(
      IntStream.range(0, last).boxed().map(i->list.subList(i, i + length))
      , IntStream.range(last, list.size()).boxed().map(i->list.subList(i, list.size()))
   );
}
lengthSequenceStream(list, 7).forEach(System.out::println);

Java9 dropWhile と takeWhile を意識した Java8 で実行する方法

昨日、以下を書いたが、、
Java9 Stream の takeWhile を意識した Java8 での方法 - Oboe吹きプログラマの黙示録
dropWhile もと思い、、改めて、dropWhile の方法も。。。

public static <T> Stream<T> dropstream(Stream<T> stream, Predicate<? super T> predicate) {
   Spliterator<T> itr = stream.spliterator();
   return StreamSupport.stream(
      new Spliterators.AbstractSpliterator<T>(itr.estimateSize(), 0){
         @Override
         public boolean tryAdvance(Consumer<? super T> consumer) {
            return itr.tryAdvance(e->{
               if (!predicate.test(e)) consumer.accept(e);
            });
         }
      }, false
   );
}

public static <T> Stream<T> whilestream(Stream<T> stream, Predicate<? super T> predicate) {
   Spliterator<T> itr = stream.spliterator();
   return StreamSupport.stream(
      new Spliterators.AbstractSpliterator<T>(itr.estimateSize(), 0) {
         boolean still = true;
         @Override
         public boolean tryAdvance(Consumer<? super T> consumer) {
            if (still){
               boolean hasNext = itr.tryAdvance(e->{
                  if (predicate.test(e)){
                     consumer.accept(e);
                  }else{
                     still = false;
                  }
               });
               return hasNext && still;
            }
            return false;
         }
      }, false
   );
}

サンプル

List<Integer> list = Stream.iterate(1, i->i+1).limit(10).collect(Collectors.toList());

System.out.println(list);
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

この1~10のリストを、4より小さければスキップしたリストにするのは、、

List<Integer> list = dropstream(list.stream(), i->i < 4).collect(Collectors.toList());

System.out.println(list2);
[4, 5, 6, 7, 8, 9, 10]

現在日より2日後~月末までの日付のリストを求めるのは、

LocalDate now = LocalDate.now();
Stream<LocalDate> nowtailDates 
= whilestream(Stream.iterate(now, d->d.plusDays(1))
  , d->!d.isAfter(LocalDate.of(now.getYear(), now.getMonthValue(), now.lengthOfMonth()))
);
List<LocalDate> list 
= dropstream(nowtailDates, d->d.isBefore(now.plusDays(2))).collect(Collectors.toList());

ということになる。
現在日=2020-4-19 なら、リストの標準出力結果は、、

[2020-04-21, 2020-04-22, 2020-04-23, 2020-04-24, 2020-04-25, 2020-04-26, 2020-04-27, 2020-04-28, 2020-04-29, 2020-04-30]

Stream 変数宣言して間を作りたくなければ、、

List<LocalDate> rlist
= dropstream(whilestream(Stream.iterate(now, d->d.plusDays(1))
      , d->!d.isAfter(LocalDate.of(now.getYear(), now.getMonthValue(), now.lengthOfMonth()))
   )
   , d->d.isBefore(now.plusDays(2))).collect(Collectors.toList()
);

Java9 Stream の takeWhile を意識した Java8 での方法

filter Predicate を頑張って書けばいいのだけど、賢くない。

public static <T> Stream<T> whilestream(Stream<T> stream, Predicate<? super T> predicate) {
   Spliterator<T> itr = stream.spliterator();
   return StreamSupport.stream(
      new Spliterators.AbstractSpliterator<T>(itr.estimateSize(), 0) {
         boolean still = true;
         @Override
         public boolean tryAdvance(Consumer<? super T> consumer) {
            if (still){
               boolean hasNext = itr.tryAdvance(e->{
                  if (predicate.test(e)){
                     consumer.accept(e);
                  }else{
                     still = false;
                  }
               });
               return hasNext && still;
            }
            return false;
         }
      }, false);
}

1から始まって10以下を println

whilestream(IntStream.iterate(1, n->n + 1).boxed(), i->i <= 10)
.forEach(System.out::println);

YearMonth のメモ

Java8 java.time.YearMonth は、
以下を見れば済むことなのだけれども、書く機会が少なかったのでメモ
https://docs.oracle.com/javase/jp/8/docs/api/java/time/YearMonth.html

YearMonth ym = YearMonth.of(2020, 12).plusMonths(3);

System.out.println(ym2.format(DateTimeFormatter.ofPattern("yyyyMM")));

標準出力結果

202103

4か月分リスト

List<YearMonth> list = Stream.iterate(YearMonth.of(2020, 12), t->t.plusMonths(1))
.limit(4)
.collect(Collectors.toList());

System.out.println(list);

標準出力結果

[2020-12, 2021-01, 2021-02, 2021-03]

日付から。。。

String str = "20201203";

List<YearMonth> list
= Stream.iterate(
   YearMonth.parse(str, DateTimeFormatter.ofPattern("yyyyMMdd"))
   , t->t.plusMonths(1)
).limit(4)
.collect(Collectors.toList());

同じ結果になる

日付リストを Stream で生成する方法について

よく考えもせずに、安易に IntStream で map 変換して作っていた。
10日分の日付リスト

List<LocalDate> list = IntStream.range(0, 10).boxed()
.map(i->LocalDate.now().plusDays(i)).collect(Collectors.toList());

java.util.stream.Stream の iterator を使えば、、、

List<LocalDate> list 
= Stream.iterate(LocalDate.now(), t->t.plusDays(1)).limit(10).collect(Collectors.toList());

IntStream → map の方法は、1日おきの10日分をつくろうとすると
ちょっと変更せねばならず、辛くなる。

List<LocalDate> list = IntStream.rangeClosed(1, 10).boxed()
.map(i->LocalDate.now().plusDays((i-1)*2)).collect(Collectors.toList());

java.util.stream.Stream の iterator を使う方法ならもっと直感的で、

List<LocalDate> list 
= Stream.iterate(LocalDate.now(), t->t.plusDays(2)).limit(10).collect(Collectors.toList());

とここまで、Java8 での話である。
Java9 以降なら、
LocalDate.datesUntil() というのがあって、

Stream<LocalDate> datesUntil(LocalDate end)
Stream<LocalDate> datesUntil(LocalDate end, Period step)

同様に、、
連日の10日分

List<LocalDate> list 
= LocalDate.now().datesUntil(LocalDate.now().plusDays(10))
.collect(Collectors.toList());

1日おきの10日分

List<LocalDate> list 
= LocalDate.now().datesUntil(LocalDate.now().plusDays(10*2), Period.ofDays(2))
.collect(Collectors.toList());

こちらは、endDate を指定することになって、ちょっと使いづらい。