I am working my way through Norvig's book on AIP. There is an exercise in it on writing a cross-product function -
(defun cross-product (fn list-1 list-2)
(mappend #'(lambda (y)
(mapcar #'(lambda (x)
(funcall fn y x))
list-2))
list-1))
(defun mappend (fn the-list)
(if (null the-list)
nil
(append (funcall fn (first the-list))
(mappend fn (rest the-list)))))
I am trying to write an implementation in Java -
interface Function<T1, T2, T3> {
public T3 function(T1 t1, T2 t2);
}
public class CrossProduct<T1, T2> {
private List<T1> list1;
private List<T2> list2;
public CrossProduct(List<T1> t1, List<T2> t2) {
this.list1 = t1;
this.list2 = t2;
}
public <T3> List<T3> calculate(Function<T1, T2, T3> fn) {
List product = new ArrayList();
for (int i = 0; i < list1.size(); i++)
for (int j = 0; j < list2.size(); j++)
product.add(fn.function(list1.get(i), list2.get(j)));
return product;
}
}
Usage -
#Test
public void testWithStrings() {
List<String> list1 = new ArrayList<String>();
list1.add("6");
list1.add("8");
List<String> list2 = new ArrayList<String>();
list2.add("2");
list2.add("3");
List<String> product = new CrossProduct<String, String>(list1, list2)
.<String> calculate(new Function<String, String, String>() {
public String function(String x, String y) {
return (String) x + (String) y;
}
});
Assert.assertEquals("62", product.get(0));
Assert.assertEquals("63", product.get(1));
Assert.assertEquals("82", product.get(2));
Assert.assertEquals("83", product.get(3));
}
Is there a better way of doing this?
It seems a little arbitrary to define your CrossProduct class that way: why are the list args member variables, whereas the fn is a method parameter? In fact, why is CrossProduct a class at all? A cross product is a list, but it's not a subtype of list, since a given list could both
be expressed as a cross product in many different ways, and
not have been constructed using the crossproduct function.
It's not natural to think of "cross product" as a type, IMO.
I would probably do something like
public class ListFunctions {
public static <T1, T2, T3> List<T3> crossProduct(List<T1> list1, List<T2> list2, Function<T1, T2, T3> fn) {
List<T3> product = new ArrayList<T3>();
for (int i = 0; i < list1.size(); i++)
for (int j = 0; j < list2.size(); j++)
product.add(fn.function(list1.get(i), list2.get(j)));
return product;
}
}
If you did want to define a class CrossProduct for some reason (e.g. to implement lazy evaluation as salman suggested), I would say it's more OO to have all three args as member variables, and have the class implement List, e.g.
public class CrossProduct<T1, T2, T3> implements List<T3> {
public CrossProduct(T1 list1, T2 list2, Function<T1, T2, T3> fn) {
// remember args...
}
// etc...
}
I don't know exactly which parameters you would like to improve. However, I would say I don't like N*M list size since it can be too big. If I knew that the result list can be immutable, then I would implement my own List which only calculates product(l1(i), l2(j)) when result.get(i*M+j-1) is called. So I have not keep a long list (perhaps just a small cache if needed).
Related
I am pretty new here, so excuse me if you do not understand my question.(Be nice :D)
So basically I have to make a method which select positives "numbers" from a list using Generics.
The base of the method should look like this :
public static <T> List<T> selectPositives(List<? extends Number> list) {
T positiveNumber = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) > 0) {
return (List<T>) positiveNumber;
}
}
return (List<T>) positiveNumber;
}
Well obviously this is not working, so I would greatly appreciate any help.
Thanks,
Alma
Using Stream API, the list of positives may be filtered out of the input:
public static <T extends Number> List<T> selectPositives(List<T> list) {
return list.stream()
.filter(x -> x.doubleValue() > 0.0)
.collect(Collectors.toList());
}
Also, List::removeIf with inverted condition may be applied to the given input/mutable copy of the input:
public static <T extends Number> List<T> selectPositives(List<T> list) {
List<T> result = new ArrayList<>(list);
result.removeIf(x -> x.doubleValue() <= 0);
return result;
}
I modified your code so that it would return a list of positive numbers.
//public static <T> List<T> selectPositives(List<? extends Number> list) {
public static <T extends Number> List<T> selectPositives(List<T> list) {
//T positiveNumber = null;
List<T> positiveNumbers = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).doubleValue() > 0) {
//return (List<T>) positiveNumber;
positiveNumbers.add(list.get(i));
}
}
return positiveNumbers;
}
public static void main(String[] args) {
List<Number> list = List.of(-1,-2,1.5, 3,-4,-5, 6);
System.out.println(selectPositives(list));
}
Output:
[1.5, 3, 6]
check for absolute value of the number, then compare it to the number without abs. if they match, then it's positive, and if not its negative.
add the elements that match to another list to have all the positive numbers in the list
As per this:
https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html
There are 2 constructors in TreeSet class:
TreeSet(Collection<? extends E> c)
TreeSet(Comparator<? super E> comparator)
I am not sure which constructor in above 2 is matched in below t2 TreeSet and whether the passed object is used or not?
cat Sorted.java
import java.util.*;
public class Sorted implements Comparable<Sorted>, Comparator<Sorted> {
private int num;
private String text;
Sorted(int n, String t) {
this.num = n;
this.text = t;
}
public String toString() { return "" + num; }
public int compareTo(Sorted s) { return text.compareTo(s.text); }
public int compare(Sorted s1, Sorted s2) {
return s1.num-s2.num;
}
public static void main(String[] args) {
Sorted s1 = new Sorted(88, "a");
Sorted s2 = new Sorted(55, "b");
TreeSet<Sorted> t1 = new TreeSet<>();
t1.add(s1); t1.add(s2);
TreeSet<Sorted> t2 = new TreeSet<>(new Sorted(1,"c"));
t2.add(s1); t2.add(s2);
System.out.println(t1 + " " + t2);
}
}
Output:
[root#localhost temp]# java Sorted
[88, 55] [55, 88]
[root#localhost temp]#
Thanks.
You're using this constructor:
TreeSet(Comparator<? super E> comparator)
Because in here:
new TreeSet<>(new Sorted(1, "c"));
You're passing a Sorted object, and Sorted is not a Collection, is a Comparator (and incidentally, also a Comparable):
public class Sorted implements Comparable<Sorted>, Comparator<Sorted>
And certainly, the passed object is used internally by TreeSet to perform its comparisons.
At first I write:
private ArrayList<Integer> getDataList() {
ArrayList<Integer> dataList = new ArrayList<>(LEN);
for (int i = 0; i < LEN; i++)
dataList.add(i);
Collections.shuffle(dataList);
return dataList;
}
Later I decide to use generic:
private <E> ArrayList<E> getDataList() {
ArrayList<E> dataList = new ArrayList<>(LEN);
for (int i = 0; i < LEN; i++)
dataList.add(/* a procedure that generates E instance from index i*/);
Collections.shuffle(dataList);
return dataList;
}
Static methods in interface are not override-able, so can't call static method on E to generate instance.
How to refactor this to use generics? Thanks.
You need to supply something that does the creation as a method parameter:
private <E> ArrayList<E> getDataList(IntFunction<? extends E> fn) {
Then:
dataList.add(fn.apply(i));
And invoke like:
List<Integer> integerList = getDataList(Integer::valueOf); // Same output as non-generic code.
List<String> stringList = getDataList(i -> "Item " + i);
Essentially, I'd like to do the following as a one-liner:
int sum = initialValue;
for (int n : collectionOfInts) {
sum += n;
}
return sum;
I see that there's http://functionaljava.org/examples/1.5/#Array.foldLeft, but I'd rather not have to copy the collection.
I see that there's http://functionaljava.org/examples/1.5/#Array.foldLeft, but I'd rather not have to copy the collection.
If you use the foldLeft from IterableW instead of Array, you won't have to copy anything.
Sorry, it still doesn't exist in Java 7. You'll have to wait for Java 8, where Closures shall be implemented.
In the meantime, you can use FunctionalJava, Guava, or a JVM-compatible, closure-enabled language such as Groovy.
Just for fun - here's how to do it without an external library:
return fold(collectionOfInts, 0, ADD);
Oh, and here's the rest :)
static <X, Y> X fold(final Iterable<? extends Y> gen, final X initial, final Function2<? super X, ? super Y, ? extends X> function) {
final Iterator<? extends Y> it = gen.iterator();
if (!it.hasNext()) {
return initial;
}
X acc = initial;
while (it.hasNext()) {
acc = function.apply(acc, it.next());
}
return acc;
}
static final Function2<Integer, Integer, Integer> ADD = new Function2<Integer, Integer, Integer>() {
#Override
public Integer apply(Integer a, Integer b) {
return a + b;
}
};
interface Function2<A, B, C> {
C apply(A a, B b);
}
2 collections are given with the same number of elements, say List<String>. What are elegant ways in JAVA to apply a functor on each 2 elements of collections with corresponding indexes?
Say, one example could be:
List<String> = { "APPLE", "PEAR" };
List<String> = { "BANANA", "ORANGE" };
A predicate that joins string together will result in the following List<String>:
List<String> = { "APPLEBANANA", "PEARORANGE" };
Akin to the functors found in Apache Commons Collections, I have created binary equivalents in the past.
For your situation, a binary transformer type object, which takes to two input objects and returns a single object, could be used. Here is some sample code that's conveys my approach:
// tranformer
interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
// general use transformer
class BinaryListUtils {
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
}
}
HTH
A quick driver of this showed it to work. Not responsible for all test cases. :-)
List<String> combineListsHorizontally(List<String> a, List<String> b) {
assert a.size() == b.size(); // just avoids some checks
List<String> result = new ArrayList<String>(a.size());
Iterator<String> itera = a.iterator();
Iterator<String> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
String combined = itera.next() + iterb.next();
result.add(combined);
}
return result;
}
If you need something generic, you would need to know they ahve a way that they can be joined
List<E> combineListsHorizontally(List<E> a, List<E> b) {
assert a.size() == b.size(); // just avoids some checks
List<E> result = new ArrayList<E>(a.size());
Iterator<E> itera = a.iterator();
Iterator<E> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
E combined = new MagicCombiner<E>(a,b).get(); // define this line yourself
result.add(combined);
}
return result;
}
///////////////// EDIT - here's a working example based off #Brents (superior) example. Props to him for illustrating this pattern better than I did.
import java.util.*;
/**
* Compile: "javac BinaryListUtils"
* Usage: "java BinaryListUtils"
C:\Documents and Settings\user\My Documents>javac BinaryListUtils.java
C:\Documents and Settings\user\My Documents>java BinaryListUtils
APPLEBANANA
PEARORANGE
C:\Documents and Settings\user\My Documents>
*/
// general use transformer
class BinaryListUtils {
// tranformer
static interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
static class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
return ret;
}
public static void main(String[] args) {
List<String> aList = new ArrayList<String>();
List<String> bList = new ArrayList<String>();
aList.add("APPLE");
aList.add("PEAR");
bList.add("BANANA");
bList.add("ORANGE");
ConcatTransformer ct = new ConcatTransformer();
List<String> cList = BinaryListUtils.collect(aList,bList,ct);
for(String s : cList) System.out.println(s);
}
}
What you're asking for isn't a predicate. It's doing a transformation on the lists zipped together. The generic way to do this is to write an iterable zipper that will zip the two lists into an iterable of a Pair, and then apply the transformation to the pairs.
I initially thought you were asking for the intersection of two collections, which is supplied in Guava collections as Sets.intersection(Set, Set).
I think your best bet here will be to do it iteratively. I can't think of any core Java API that can do it.
public List<String> predicate(List<String> list1, List<String> list2) {
List<String> list = new ArrayList<String>();
for(int i = 0; i < list1.size(); i++) {
list.add(new StringBuilder(list1.get(i)).append(list2.get(i)).toString());
}
return list;
}
Haven't compiled / run it. Good luck.