-
Notifications
You must be signed in to change notification settings - Fork 0
/
BagV.java
131 lines (116 loc) · 3.05 KB
/
BagV.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* From "Subtyping, Sublcassing, and Trouble with OOP"
* http://okmij.org/ftp/Computation/Subtyping
*/
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* <code>BagV</code> implements an immutable multiset.
*/
public class BagV
{
/**
* Constructs an empty bag
*/
public BagV()
{
this(Collections.emptyList());
}
/**
* The number of elements in the bag
*/
public int size()
{
return elements.size();
}
/**
* Put an element into the bag
*/
public BagV put(final Integer elem)
{
return new BagV(Stream.concat(elements.stream(), Stream.of(elem)).collect(Collectors.toList()));
}
/**
* Count the number of occurrences of a particular element in the bag
*/
public int count(final Integer elem)
{
return (int) elements.stream().filter(elem::equals).count();
}
/**
* Remove an element from the bag
*/
public BagV del(final Integer elem)
{
final List<Integer> newElements = new ArrayList<Integer>(elements);
newElements.remove(elem);
return new BagV(newElements);
}
/**
* Return a stream for the elements in this bag
*/
public Stream<Integer> stream()
{
return elements.stream();
}
/**
* Standard "print-on" operation
*
* N.B.: We use only publicly-available methods here
*/
public static void write(final OutputStream os, final BagV bag)
{
new PrintStream(os, true).println(bag.stream().map(String::valueOf).collect(Collectors.joining(",", "[", "]")));
}
/**
* Union (merge) of the two bags
*
* N.B.: We use only publicly-available methods here
*/
public static BagV union(final BagV to, final BagV from)
{
return from.elements.stream().reduce(to, BagV::put, BagV::union);
}
/**
* Determine whether BagV a is a subbag of BagV b
*
* N.B.: We use only publicly-available methods here
*/
public static boolean isSubbag(final BagV a, final BagV b)
{
return a.stream().map(elem -> a.count(elem) == b.count(elem)).reduce(true, Boolean::logicalAnd);
}
/**
* Determine whether BagV a is a superbag of BagV b
*
* N.B.: We use only publicly-available methods here
*/
public static boolean isSuperbag(final BagV a, final BagV b)
{
return isSubbag(b, a);
}
/**
* Structural equivalence of the bags
* Two bags are equal if they contain the same number of the same elements
*
* N.B.: We use only publicly-available methods here
*/
public static boolean equals(final BagV a, final BagV b)
{
return isSubbag(a, b) && isSuperbag(a, b);
}
////////////////////////////////////////////////////////////////////////////
//
// Private implementation
//
private BagV(final List<Integer> elements)
{
this.elements = Collections.unmodifiableList(elements);
}
private final List<Integer> elements;
}