2

During the reading SICP I encouraged with Exercise 2.32.

We can represent a set as a list of distinct elements, and we can represent the set of all subsets of the set as a list of lists. For example, if the set is (1 2 3 4), then the set of all subsets is (() (4) (3) (3 4) (2) (2 4) (2 3) (2 3 4) (1) (1 4) (1 3) (1 3 4) (1 2) (1 2 4) (1 2 3) (1 2 3 4)). Complete the following definition of a procedure that generates the set of subsets of a set and give a clear explanation of why it works:

(define (subsets s)
  (if (null? s)
      (list nil)
      (let ((rest (subsets (cdr s))))
        (append rest (map ⟨??⟩ rest)))))
(define (subset s)
     (if (null? s)
         (list '())
         (let ((rest (subset (cdr s))))
             (append
                  rest (map (lambda (x) (cons (car s) x)) rest)
             )
         )))

(subset '(1 2 3 4))
1 ]=> 
;Value 15: (() (4) (3) (3 4) (2) (2 4) (2 3) (2 3 4) (1) (1 4) (1 3) (1 3 4) (1 2) (1 2 4) (1 2 3) (1 2 3 4))

I could do it with schema, but after it I wondered: "How would I can do with java?". I thought about it because I could`t understand why it should work if we got in each recursion a sublist from the previous one.

Of course I can solute it in another way. For instance, with this approach: all possible combinations 2^N-1, for our case this is 2^4-1

number binary result
1      0001    (4)
2      0010    (3)
3      0011    (3,4)
4      0100    (2)
5      0101    (2,4)
6      0110    (2,3)
7      0111    (2,3,4)
8      1000    (1)
9      1001    (1,4)
10     1010    (1,3)
11     1011    (1,3,4)
12     1100    (1,2)
13     1101    (1,2,4)
14     1110    (1,2,3)
15     1111    (1,2,3,4)

I rewrited a little scheme code to similarity with java one

(define (subset s)
     (if (null? s)
         (list '())
         ((lambda (rest)
                 (append rest (map (lambda (x) (cons (car s) x)) rest))
         )(subset (cdr s)))
     )
)
(subset '(1 2 3))
1 ]=> 
;Value 19: (() (4) (3) (3 4) (2) (2 4) (2 3) (2 3 4) (1) (1 4) (1 3) (1 3 4) (1 2) (1 2 4) (1 2 3) (1 2 3 4))

I wrote my java implementation

import java.util.*;
import java.util.function.UnaryOperator;

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.*;

public class A {
    public static void main(String[] args) {
        List<Integer> l = new ArrayList<>(asList(1,2,3));

        System.out.println(subset(l));
    }

    private static List<List<Integer>> subset(final List<Integer> s) {
        if (s.isEmpty()) return new ArrayList<>();

        final UnaryOperator<List<List<Integer>>> f = (final List<List<Integer>> rest) -> {
            final List<List<Integer>> collect = rest.stream()
                    .map(x -> {
                        List<Integer> r = new ArrayList<>();
                        r.add(s.get(0));
                        r.addAll(x);

                        return r;
                    })
                    .collect(toList());

            rest.addAll(collect);

            return rest;
        };

        return f.apply(subset(new ArrayList<>(s.subList(1, s.size()))));
    }

}

In java I have the empty list (I changed Set to List in order to get by the index 0 without any tricks). And as I mentioned before I understand why my java returns the empty list, but I don`t understand how to fix my java code that it behavior matches scheme.

rsm
  • 2,530
  • 4
  • 26
  • 33
  • @azurefrog Yes, I understand it. I decided to rewrite this code from scheme to java because I noticed it and did not understand how it works in scheme. Or may be I don`t understand something in scheme code or somewhere semantics of this languages a little different? – Yuri Glushenkov Jul 19 '19 at 21:20
  • The set of all subsets is called the power set. See it implemented [here](https://rosettacode.org/wiki/Power_set) in numerous languages. – Kaz Jul 20 '19 at 01:09

1 Answers1

3

Your base case is wrong. The scheme expression (list '()) doesn't evaluate to an empty list: it evaluates to a one-element list, whose element is the empty list. In Java, you've written new ArrayList<>() as the base case, which is an empty list. Instead, use something like Arrays.asList(new ArrayList<>()).

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • 2
    Replacing the OP's return statement with `return new ArrayList<>(Arrays.asList(new ArrayList<>()));` made the program work for me. Just `return Arrays.asList(new ArrayList<>());` threw an `UnsupportedOperationException`. – azurefrog Jul 20 '19 at 01:00