recursion instead of multi-loops - java

I want this method to work for any given number of arguments, i can do that with code generation(with a lot of ugly code), can it be done with recursion? if so how? I understand recursion, but i dont know how to write this.
private static void allCombinations(List<String>... lists) {
if (lists.length == 3) {
for (String s3 : lists[0]) {
for (String s1 : lists[1]) {
for (String s2 : lists[2]) {
System.out.println(s1 + "-" + s2 + "-" + s3);
}
}
}
}
if (lists.length == 2) {
for (String s3 : lists[0]) {
for (String s1 : lists[1]) {
System.out.println(s1 + "-" + s3);
}
}
}
}

Here is a simple recursive implementation:
private static void allCombinations(List<String>... lists) {
allCombinations(lists, 0, "");
}
private static void allCombinations(List<String>[] lists, int index, String pre) {
for (String s : lists[index]) {
if (index < lists.length - 1) {
allCombinations(lists, index + 1, pre + s + "-");
}else{
System.out.println(pre + s);
}
}
}

Do you particularly need it to be recursive? I'd make it non-recursive but still not special case things:
public static void allCombinations(List<String>... lists) {
int[] indexes = new int[lists.length];
while (incrementIndexes(lists, indexes)) {
StringBuilder builder = new StringBuilder();
for (int i=0; i < indexes.length; i++) {
if (i != 0) {
builder.append("-");
}
builder.append(lists[i].get(indexes[i]));
}
System.out.println(builder);
}
}
private static boolean incrementIndexes(List<String>[] lists, int[] indexes) {
for (int depth = indexes.length-1; depth >= 0; depth--) {
indexes[depth]++;
if (indexes[depth] != lists[depth].size()) {
return true;
}
// Overflowed this index. Reset to 0 and backtrack
indexes[depth] = 0;
}
// Everything is back to 0. Finished!
return false;
}

Here's a generalised recursive version. It complains about unchecked generic array creation in the test code, but the permute code itself is okay:
import java.util.*;
public class Test
{
public interface Action<T> {
void execute(Iterable<T> values);
}
public static void main(String[] args) {
List<String> first = Arrays.asList(new String[]{"1", "2", "3"});
List<String> second = Arrays.asList(new String[]{"a", "b", "c"});
List<String> third = Arrays.asList(new String[]{"x", "y"});
Action<String> action = new Action<String>() {
#Override public void execute(Iterable<String> values) {
StringBuilder builder = new StringBuilder();
for (String value : values) {
if (builder.length() != 0) {
builder.append("-");
}
builder.append(value);
}
System.out.println(builder);
}
};
permute(action, first, second, third);
}
public static <T> void permute(Action<T> action, Iterable<T>... lists) {
Stack<T> current = new Stack<T>();
permute(action, lists, 0, current);
}
public static <T> void permute(Action<T> action, Iterable<T>[] lists,
int index, Stack<T> current) {
for (T element : lists[index]) {
current.push(element);
if (index == lists.length-1) {
action.execute(current);
} else {
permute(action, lists, index+1, current);
}
current.pop();
}
}
}

here's my recursive solution with correct ordering, based on Rasmus' solution. it works only if all lists are of same size.
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> first = Arrays.asList(new String[]{"1", "2", "3"});
List<String> second = Arrays.asList(new String[]{"a", "b", "c"});
List<String> third = Arrays.asList(new String[]{"x", "y", "z"});
allCombinations (first, second, third);
}
private static void allCombinations(List<String>... lists) {
allCombinations(lists, 1, "");
}
private static void allCombinations(List<String>[] lists, int index, String pre) {
int nextHop = hop(index, lists.length-1);
for (String s : lists[index]) {
if (index != 0) {
allCombinations(lists, nextHop, pre + s + "-");
} else System.out.println(pre + s);
}
}
private static int hop(int prevIndex, int maxResult){
if (prevIndex%2 == 0){
return prevIndex-2;
} else {
if (prevIndex == maxResult)
return prevIndex-1;
int nextHop = prevIndex+2;
if (nextHop > maxResult){
return maxResult;
} else return nextHop;
}
}
}
a "correct ordering" solution that allows lists of different sizes will have to start from the last list and work it's way backwards to the first list (lists[0]), appending the element at either beginning or end of the "pre" string and passing it onward. again, the first list will print the result. I'd have coded that, but lunch is ready and girlfriend is beginning to dislike stackoverflow...

Related

Compare Lists in ArrayList

I have a text file containing the following strings (which are versions of a software):
1_10_2_0_154
3_10_5_2_10
2_10_4_1
3_10_5_1_37
I'm trying to find the most recent version, in this case 3_10_5_2_10 is the version that I'm trying to display using java.
For the moment, here is my code:
BufferedReader br;
String version;
ArrayList<List<Integer>> array = new ArrayList<List<Integer>>();
List<Integer> liste = new ArrayList<Integer>();
try{
br = new BufferedReader(new FileReader(new File(FILEPATH)));
while((version= br.readLine()) != null)
{
liste = Arrays.asList(version.split("_")).stream().
map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
array.add(liste);
}
for(int i = 0; i < array.size(); i++)
{
for (List l: array)
{
Object z = l.get(i);
List<Object> listes = new ArrayList<Object>();
listes.add(z);
System.out.println(listes);
}
}
br.close();
System.out.println(array);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
I made a loop to save strings to ArrayList> like:
[[1,10,2,0,154] , [3,10,5,2,10], [2,10,4,1], [3,10,5,1,37]]
I want to get the elements of each list and compare them to find the most biggest one (most recent one) but I don't know to do that..
I sugguest you a object approach, define a class named Version with compareTo method, then using method sort on Collections class you can simply sort your versions.
Advantages
Clean and Clear code
Data validation
Main:
public class Main {
public static void main(String[] args){
List<Version> versions = Arrays.asList(
Version.create("1_10_2_0_154"),
Version.create("3_10_5_2_10"),
Version.create("2_10_4_1_49"),
Version.create("3_10_5_1_37"));
versions.sort(Version::compareTo);
System.out.println(versions.get(0).toString());
}
}
Version:
public class Version implements Comparable<Version> {
private final int major;
private final int minor;
private final int bug;
private final int release;
private final int build;
public Version(int major, int minor, int bug, int release, int build) {
this.major = major;
this.minor = minor;
this.bug = bug;
this.release = release;
this.build = build;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getBug() {
return bug;
}
public int getRelease() {
return release;
}
public int getBuild() {
return build;
}
#Override
public String toString() {
return "Version{" +
"major=" + major +
", minor=" + minor +
", bug=" + bug +
", release=" + release +
", build=" + build +
'}';
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return create(intValues);
}
public static Version create(List<Integer> values){
if(Objects.requireNonNull(values).size() < 5)
throw new IllegalArgumentException();
return new Version(
values.get(0),
values.get(1),
values.get(2),
values.get(3),
values.get(4)
);
}
#Override
public int compareTo(Version that) {
if (this.major > that.major) {
return -1;
} else if (this.major < that.major) {
return 1;
}
if (this.minor > that.minor) {
return -1;
} else if (this.minor < that.minor) {
return 1;
}
if (this.bug > that.bug) {
return -1;
} else if (this.bug < that.bug) {
return 1;
}
if (this.release > that.release) {
return -1;
} else if (this.release < that.release) {
return 1;
}
if (this.build > that.build) {
return -1;
} else if (this.build < that.build) {
return 1;
}
return 0;
}
}
UPDATE 1
As suggested by #Henrik i updated the list sorting with a Java 8 approach.
UPDATE 2
I reversed the compareTo method so now you can simply do plain sort calling sort method on list and passing method reference Version::compareTo
UPDATE 3
A more dynamic solution for Version class:
public class Version implements Comparable<Version> {
private final List<Integer> values;
public Version(List<Integer> values) {
this.values = values;
}
public List<Integer> getValues() {
return values;
}
#Override
public String toString() {
return String.join("_", values
.stream()
.map(Object::toString)
.collect(Collectors.toList()));
}
#Override
public int compareTo(Version that) {
List<Integer> thatValues = that.getValues();
for(int index = 0; index < values.size(); index++){
Integer value = values.get(index);
Integer thatValue = thatValues.get(index);
if (value > thatValue) {
return -1;
} else if (value < thatValue) {
return 1;
}
}
return 0;
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return new Version(intValues);
}
}
You can write a Comparator to compare two Lists
Comparator<List<Integer>> comparator = (list1, list2) -> {
Iterator<Integer> iteratorA = list1.iterator();
Iterator<Integer> iteratorB = list2.iterator();
//It iterates through each list looking for an int that is not equal to determine which one precedes the other
while (iteratorA.hasNext() && iteratorB.hasNext()) {
int elementA = iteratorA.next();
int elementB = iteratorB.next();
if (elementA > elementB) {
return 1;
} else if (elementA < elementB) {
return -1;
}
}
//All elements seen so far are equal. Use the list size to decide
return iteratorA.hasNext() ? 1 : iteratorB.hasNext() ? -1 : 0;
};
You can sort it as
Collections.sort(list, comparator);
EDIT: You can refer to David Geirola's answer to convert the version string as a POJO and move the comparator logic inside that. But that is highly tied/coupled to the input string format. My solution works for any List<List<Integer>>.
A simple object oriented approach would be to create object, representing version number, let's call it VersionNumber, which would have a constructor of a factory method that does the parsing of the string. This VersionNumber class should implement interface Comparable and implement method compareTo.
Here is a hint for using Comparable Why should a Java class implement comparable?
Then you can easily write an algorithm to find the max version or google some library that would do it for you.
It is not optimized but should work. You can use both of comparators.
static List<String> versions = Arrays.asList(
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37");
static Comparator<List<Integer>> c = (o1,o2) -> {
int length = o1.size()>o2.size()?o2.size():o1.size();
for (int i = 0; i < length; i++) {
int i1 = o1.get(i);
int i2 = o2.get(i);
if (i1 != i2)
return i1 - i2;
}
return 0;
};
static Comparator<List<Integer>> c2 = (o1,o2) -> {
Iterator<Integer> i1=o1.iterator();
Iterator<Integer> i2=o2.iterator();
while (i1.hasNext() && i2.hasNext()){
int i = i1.next()-i2.next();
if (i!=0) return i;
}
return 0;
};
static Optional<List<Integer>> getTheMostRecentVersion(List<String> versions) {
return versions.stream().
map(s -> Arrays.stream(s.split("_")).
map(Integer::parseInt).
collect(Collectors.toList())).max(c2);
}
I think that this text file could be very big and it is better to compare each line on the fly (instead of store all line into collection to sort it after):
public static String getMostRecentVersion(BufferedReader in) throws IOException {
final Comparator<String[]> version = (s1, s2) -> {
int res = 0;
for (int i = 0; i < 5 && res == 0; i++)
res = Integer.compare(Integer.parseInt(s1[i]), Integer.parseInt(s2[i]));
return res;
};
String str;
String resStr = null;
String[] resPparts = null;
while ((str = in.readLine()) != null) {
String[] parts = str.split("_");
if (resStr == null || version.compare(parts, resPparts) > 0) {
resStr = str;
resPparts = parts;
}
}
return resStr;
}
A general ListComparator should help.
static class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {
#Override
public int compare(List<T> o1, List<T> o2) {
for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
int diff =
// Off the end of both - same.
i >= o1.size() && i >= o2.size() ? 0
// Off the end of 1 - the other is greater.
: i >= o1.size() ? -1
: i >= o2.size() ? 1
// Normal diff.
: o1.get(i).compareTo(o2.get(i));
if (diff != 0) {
return diff;
}
}
return 0;
}
}
private static final Comparator<List<Integer>> BY_VERSION = new ListComparator<Integer>().reversed();
public void test(String[] args) {
String[] tests = {
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37",
"3_10_5_1_37_0"
};
System.out.println("Before: " + Arrays.toString(tests));
System.out.println("After: " + Arrays.stream(tests)
// Split into parts.
.map(s -> s.split("_"))
// Map String[] to List<Integer>
.map(a -> Arrays.stream(a).map(s -> Integer.valueOf(s)).collect(Collectors.toList()))
// Sort it.
.sorted(BY_VERSION)
// Back to a new list.
.collect(Collectors.toList()));
}
slap your arrays together into a number then just do number comparison.
class Scratch
{
public static void main(String[] args)
{
List<List<Integer>> arr = new ArrayList<>();
arr.add(fromArray(new Integer[]{1,10,2,0,154}));
arr.add(fromArray(new Integer[]{3,10,5,2,10}));
arr.add(fromArray(new Integer[]{2,10,4,1,49}));
arr.add(fromArray(new Integer[]{3,10,5,1,37}));
Integer[] maxLengths = {0,0,0,0,0};
for (List<Integer> v : arr)
{
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int curMaxLen = maxLengths[idx];
maxLengths[idx] = Math.max(n.toString().length(), curMaxLen);
}
}
Long largest = arr.stream().map(v -> {
StringBuilder result = new StringBuilder();
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int maxLen = maxLengths[idx];
result.append(String.format("%-" + maxLen + 's', n).replace(' ', '0'));
}
return result.toString();
}).map(Long::valueOf).max(Comparator.naturalOrder()).get();
System.out.println(largest);
}
public static List<Integer> fromArray(Integer[] array)
{
List<Integer> list = new ArrayList<>();
Collections.addAll(list, array);
return list;
}
}

How to convert an Array method to an ArrayList method?

How can I alter the below method to work with an ArrayList?
I was thinking something like this:
public static boolean sortArrayList(ArrayList<Integer> list) {
return false;
}
but i'm not sure how to complete it.
Here is the method that I am trying to convert from working with an Array to instead work with an ArrayList:
public static boolean sortArrayList(final int[] data) {
for(int i = 1; i < data.length; i++) {
if(data[i-1] > data[i]) {
return false;
}
}
return true;
}
public static boolean sortArrayList(final ArrayList <Integer> data) {
for (int i = 1; i < data.size(); i++) {
if (data.get(i - 1) > data.get(i)) {
return false;
}
}
return true;
}
I have a few problems with the accepted answer, as given by #Sanj: (A) it doesn't handle nulls within the list, (B) it is unnecessarily specialized to ArrayList<Integer> when it could easily be merely Iterable<Integer>, and (C) the method name is misleading.
NOTE: For (A), it's quite possible that getting an NPE is appropriate - the OP didn't say. For the demo code, I assume that nulls are ignorable. Other interpretations a also fair, e.g. null is always a "least" value (requiring different coding, LAAEFTR). Regardless, the behaviour should be JavaDoc'ed - which I didn't do in my demo #8>P
NOTE: For (B), keeping the specialized version might improve runtime performance, since the method "knows" that the backing data is in an array and the compiler might extract some runtime efficiency over the version using an Iterable but such claim seem dubious to me and, in any event, I would want to see benchmark results to support such. ALSO Even the version I demo could be further abstracted using a generic element type (vs limited to Integer). Such a method might have definition like:
public static <T extends Comparable<T>> boolean isAscendingOrder(final Iterable<T> sequence)
NOTE: For (C), I follow #Valentine's method naming advice (almost). I like the idea so much, I took it one step further to explicitly call out the directionality of the checked-for-sortedness.
Below is a demonstration class that shows good behaviour for a isAscendingOrder which address all those issues, followed by similar behaviour by #Sanj's solution (until the NPE). When I run it, I get console output:
true, true, true, true, false, true
------------------------------------
true, true, true, true, false,
Exception in thread "main" java.lang.NullPointerException
at SortCheck.sortArrayList(SortCheck.java:35)
at SortCheck.main(SortCheck.java:78)
.
import java.util.ArrayList;
public class SortCheck
{
public static boolean isAscendingOrder(final Iterable<Integer> sequence)
{
Integer prev = null;
for (final Integer scan : sequence)
{
if (prev == null)
{
prev = scan;
}
else
{
if (scan != null)
{
if (prev.compareTo(scan) > 0)
{
return false;
}
prev = scan;
}
}
}
return true;
}
public static boolean sortArrayList(final ArrayList<Integer> data)
{
for (int i = 1; i < data.size(); i++)
{
if (data.get(i - 1) > data.get(i))
{
return false;
}
}
return true;
}
private static ArrayList<Integer> createArrayList(final Integer... vals)
{
final ArrayList<Integer> rval = new ArrayList<>();
for(final Integer x : vals)
{
rval.add(x);
}
return rval;
}
public static void main(final String[] args)
{
final ArrayList<Integer> listEmpty = createArrayList();
final ArrayList<Integer> listSingleton = createArrayList(2);
final ArrayList<Integer> listAscending = createArrayList(2, 5, 8, 10 );
final ArrayList<Integer> listPlatuea = createArrayList(2, 5, 5, 10 );
final ArrayList<Integer> listMixedUp = createArrayList(2, 5, 3, 10 );
final ArrayList<Integer> listWithNull = createArrayList(2, 5, 8, null);
System.out.print(isAscendingOrder(listEmpty ) + ", ");
System.out.print(isAscendingOrder(listSingleton) + ", ");
System.out.print(isAscendingOrder(listAscending) + ", ");
System.out.print(isAscendingOrder(listPlatuea ) + ", ");
System.out.print(isAscendingOrder(listMixedUp ) + ", ");
System.out.print(isAscendingOrder(listWithNull ) + "\n");
System.out.println("------------------------------------");
System.out.print(sortArrayList(listEmpty ) + ", ");
System.out.print(sortArrayList(listSingleton) + ", ");
System.out.print(sortArrayList(listAscending) + ", ");
System.out.print(sortArrayList(listPlatuea ) + ", ");
System.out.print(sortArrayList(listMixedUp ) + ", ");
System.out.print(sortArrayList(listWithNull ) + "\n");
}
}
Try below function, it takes integer array and converts it into a ArrayList and then computes the result :
public static boolean sortArrayList(final int[] data) {
List<Integer> aList = new ArrayList<Integer>();
for (int index = 0; index < data.length; index++)
aList.add(data[index]);
for (int i = 1; i < aList.size(); i++) {
if (aList.get(i - 1) > aList.get(i)) {
return false;
}
}
return true;
}

How to join items of list, but use a different delimiter for the last item?

Given list like:
List<String> names = Lists.newArrayList("George", "John", "Paul", "Ringo")
I'd like to transform it to a string like this:
George, John, Paul and Ringo
I can do it with rather clumsy StringBuilder thing like so:
String nameList = names.stream().collect(joining(", "));
if (nameList.contains(",")) {
StringBuilder builder = new StringBuilder(nameList);
builder.replace(nameList.lastIndexOf(','), nameList.lastIndexOf(',') + 1, " and");
return builder.toString();
}
Is there a bit more elegant approach? I don't mind using a library if needed.
NOTES:
I could use an old for loop with an index, but I am not looking for such a solution
There are no commas within the values (names)
I'm not sure how elegant this is, but it works. The annoying part is that you have to reverse the List.
List<String> list = Arrays.asList("George", "John", "Paul", "Ringo");
String andStr = " and ";
String commaStr = ", ";
int n = list.size();
String result = list.size() == 0 ? "" :
IntStream.range(0, n)
.mapToObj(i -> list.get(n - 1 - i))
.reduce((s, t) -> t + (s.contains(andStr) ? commaStr : andStr) + s)
.get();
System.out.println(result);
However, I think the best solution is this.
StringBuilder sb = new StringBuilder();
int n = list.size();
for (String string : list) {
sb.append(string);
if (--n > 0)
sb.append(n == 1 ? " and " : ", ");
}
System.out.println(sb);
It's clear, efficient, and obviously works. I don't think Streams are a good fit for this problem.
As you already did most of it I would introduce a second method "replaceLast" which is not in the JDK for java.lang.String so far:
import java.util.List;
import java.util.stream.Collectors;
public final class StringUtils {
private static final String AND = " and ";
private static final String COMMA = ", ";
// your initial call wrapped with a replaceLast call
public static String asLiteralNumeration(List<String> strings) {
return replaceLast(strings.stream().collect(Collectors.joining(COMMA)), COMMA, AND);
}
public static String replaceLast(String text, String regex, String replacement) {
return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement);
}
}
You might change the delimiters and params as well. Here the test for your requirements so far:
#org.junit.Test
public void test() {
List<String> names = Arrays.asList("George", "John", "Paul", "Ringo");
assertEquals("George, John, Paul and Ringo", StringUtils.asLiteralNumeration(names));
List<String> oneItemList = Arrays.asList("Paul");
assertEquals("Paul", StringUtils.asLiteralNumeration(oneItemList));
List<String> emptyList = Arrays.asList("");
assertEquals("", StringUtils.asLiteralNumeration(emptyList));
}
You may join all the elements except the last by using a sublist:
String nameList =
names.isEmpty() ? "" :
names.subList(0, names.size() - 1)
.stream()
.collect(Collectors.joining(firstDelimiter))
+ ((names.size() > 1) ? secondDelimiter + names.get(names.size() - 1) : names.get(0))
;
Personally, I don't like this approach because for non-array backed list implementations, the time of List#get may be O(n).
Tested here:
static String joinList(List<String> names) {
return joinList(names, ", ", " and ");
}
static String joinList(List<String> names, String firstDelimiter, String secondDelimiter) {
return names.isEmpty() ? "" :
names.subList(0, names.size() - 1)
.stream()
.collect(Collectors.joining(firstDelimiter))
+ ((names.size() > 1) ? secondDelimiter+ names.get(names.size() - 1) : names.get(0))
;
}
public static void main(String[] args) {
System.out.println(joinList(Arrays.asList("George", "John", "Paul", "Ringo")));
System.out.println(joinList(Arrays.asList("Ringo")));
System.out.println(joinList(Arrays.asList()));
System.out.println(joinList(null)); //this one throws NPE as OP oddly requested
}
Here's an alternative implementation or joinList, which may make it clearer what actually happens:
static String joinList(List<String> names, String firstDelimiter, String secondDelimiter) {
if (names.isEmpty()) {
return "";
} else if (names.size() == 1) {
return names.get(0);
} else {
return names.subList(0, names.size() - 1)
.stream().collect(Collectors.joining(firstDelimiter))
+ secondDelimiter + names.get(names.size() - 1);
}
}
If you don't mind using an Iterator, this works:
private static String specialJoin(Iterable<?> list, String sep, String lastSep) {
StringBuilder result = new StringBuilder();
final Iterator<?> i = list.iterator();
if (i.hasNext()) {
result.append(i.next());
while (i.hasNext()) {
final Object next = i.next();
result.append(i.hasNext() ? sep : lastSep);
result.append(next);
}
}
return result.toString();
}
It can probably be rewritten as a collector easily enough by someone who is familiar with that api.
Here's an elegant solution using the streams api:
String nameList = names.stream().collect(naturalCollector(", ", " and "));
Unfortunatley, it depends on this function, that could be stashed away in some utility class:
public static Collector<Object, Ack, String> naturalCollector(String sep, String lastSep) {
return new Collector<Object, Ack, String>() {
#Override public BiConsumer<Ack, Object> accumulator() {
return (Ack a, Object o) -> a.add(o, sep);
}
#Override public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.emptySet();
}
#Override public BinaryOperator<Ack> combiner() {
return (Ack one, Ack other) -> one.merge(other, sep);
}
#Override public Function<Ack, String> finisher() {
return (Ack a) -> a.toString(lastSep);
}
#Override public Supplier<Ack> supplier() {
return Ack::new;
}
};
}
... and also on this class, which is an internal stateholder in the above function, but which the Collector API wants exposed:
class Ack {
private StringBuilder result = null;
private Object last;
public void add(Object u, String sep) {
if (last != null) {
doAppend(sep, last);
}
last = u;
}
private void doAppend(String sep, Object t) {
if (result == null) {
result = new StringBuilder();
} else {
result.append(sep);
}
result.append(t);
}
public Ack merge(Ack other, String sep) {
if (other.last != null) {
doAppend(sep, last);
if (other.result != null) {
doAppend(sep, other.result);
}
last = other.last;
}
return this;
}
public String toString(String lastSep) {
if (result == null) {
return last == null ? "" : String.valueOf(last);
}
result.append(lastSep).append(last);
return result.toString();
}
}
If commas are never in the values, it's a one-liner:
String all = names.toString().replaceAll("^.|.$", "").replaceAll(",(?!.*,)", " and");
You can have write a custom function to add the last delimiter, but for delimiter in between you can use StringUtils.join() to accomplish your task.Check this link for api

How to sort the arrays in ArrayList?

I have ArrayList it contains so many arrays, each array contain first name, last name. now I want to sort the list based on the last name.
Example:
ArrayList<String[]> list=new ArrayList<String[]>();
String[] name1={"koti" ,"reddy"};
String[] name2={"hanu" ,"sanjay"};
String[] name3={"ajay" ,"zedeja"};
String[] name4={"basha" ,"kadhar"};
list.add(name1);
list.add(name2);
list.add(name3);
list.add(name4);
I want the sorting order like:
basha kadhar
koti reddy
hanu sanjay
ajay zedeja
Could you please help on this ASAP, Thanks in Advance
Write a custom Comparator and supply that to the appropriate sort overload along with the data.
However, I would recommend a separate Person/Name type, instead of String arrays, as it will make data easier to keep track of and it could implement Comparable (which would eliminate/replace the need of a Comparator).
Now, when writing an applicable compare/compareTo, the code should look similar to:
int cmpLastName = a_lastName.compareTo(b_lastName);
if (cmpLastName == 0) {
// same lastname, order now based on first name
return a_firstName.compareTo(b_firstName);
} else {
// different lastname, so have enough ordering
return cmpLastName;
}
try this
Collections.sort(list, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
int c = o1[0].compareTo(o2[0]);
if (c != 0) {
return c;
}
return o1[1].compareTo(o2[1]);
}
});
This is how I would perform that sort operation.
public static void main(String[] args) {
ArrayList<String[]> list = new ArrayList<String[]>();
String[] name1 = { "koti", "reddy" };
String[] name2 = { "hanu", "sanjay" };
String[] name3 = { "ajay", "zedeja" };
String[] name4 = { "basha", "kadhar" };
list.add(name1);
list.add(name2);
list.add(name3);
list.add(name4);
System.out.println("Before sorting");
for (String[] r : list) {
System.out.println(Arrays.toString(r));
}
Collections.sort(list, new Comparator<String[]>() {
public int compare(String[] left, String[] right) {
if (left == null) { // null?
if (right == null) { // null == null!
return 0;
}
return -1; // null < not(null)
} else if (right == null) {
return 1; // not(null) > null.
}
// If the last names aren't the same, return the result
// of comparing the last names.
if (left[1].compareTo(right[1]) != 0) {
return left[1].compareTo(right[1]);
}
// Return the result of comparing the first names.
return left[0].compareTo(right[0]);
}
});
System.out.println("After sorting");
for (String[] r : list) {
System.out.println(Arrays.toString(r));
}
}
try this code to achieve your output.
public static void main(String []args){
ArrayList<String[]> list=new ArrayList<String[]>();
String[] name1={"koti" ,"reddy"};
String[] name2={"hanu" ,"sanjay"};
String[] name3={"ajay" ,"zedeja"};
String[] name4={"basha" ,"kadhar"};
list.add(name1);
list.add(name2);
list.add(name3);
list.add(name4);
Collections.sort(list, new Comparator<String[]>() {
#Override
public int compare(String[] s1, String[] s2) {
int i = s1[0].compareTo(s2[0]);
if (i != 0) {
return i;
}
return s1[1].compareTo(s2[1]);
}
});
System.out.println("after sorting"+"\n");
for (String[] s : list) {
for(int i=0;i<s.length;i++){
System.out.print(s[i]+"\t");
}
System.out.print("\n");
}
}

Test all possible combinations of rows

The problem is the following. There are multiple rows that have non-unique identifiers:
id value
0: {1,2,3}
0: {1,2,2}
1: {1,2,3}
2: {1,2,3}
2: {1,1,3}
I have the function equals that can compare multiple rows between each other. I need to write a code that selects the rows as an input of the function equals. The rows selected must have unique ids, BUT I should check all possible combinations of unique ids. For instance, if there are 5 rows with ids: 0,0,1,2,3, then I should check the following two combinations of ids: 0,1,2,3 and 0,1,2,3, because 0 apears twice. Of course, each of these two combinations will consist of unique rows that have id=0.
My code snippet is the following:
public class Test {
public static void main(String[] args) {
ArrayList<Row> allRows = new ArrayList<Row>();
allRows.add(new Row(0,new int[]{1,2,3}));
allRows.add(new Row(0,new int[]{1,2,2}));
allRows.add(new Row(1,new int[]{1,2,3}));
allRows.add(new Row(2,new int[]{1,2,3}));
allRows.add(new Row(2,new int[]{1,1,3}));
boolean answer = hasEqualUniqueRows(allRows);
}
private boolean hasEqualUniqueRows(ArrayList<Row> allTokens) {
for (int i=0; i<allTokens.size(); i++) {
ArrayList<Integer[]> rows = new ArrayList<Integer[]>();
rows = findUniqueRows(i,allTokens);
boolean answer = equalsExceptForNulls(rows);
if (answer) return true;
}
return false;
}
// Compare rows for similarities
public static <T> boolean equalsExceptForNulls(ArrayList<T[]> ts) {
for (int i=0; i<ts.size(); i++) {
for (int j=0; j<ts.size(); j++) {
if (i != j) {
boolean answer = equals(ts.get(i),ts.get(j));
if (!answer) return false;
}
}
}
return true;
}
public static <T> boolean equals(T[] ts1, T[] ts2) {
if (ts1.length != ts2.length) return false;
for(int i = 0; i < ts1.length; i++) {
T t1 = ts1[i], t2 = ts2[i];
if (t1 != null && t2 != null && !t1.equals(t2))
return false;
}
return true;
}
class Row {
private String key;
private Integer[] values;
public Row(String k,Integer[] v) {
this.key = k;
this.values = v;
}
public String getKey() {
return this.key;
}
public Integer[] getValues() {
return this.values;
}
}
}
Since the number of rows with unique ids is apriori unknown, I don´t know how to solve this problem. Any suggestions? Thanks.
Edit#1
I updated the code. Now it´s more complete. But it lacks the implementation of the function findUniqueRows. This function should select rows from the ArrayList that have unique keys (ids). Could someone help me to develop this function? Thanks.
Assuming the objective is to find every combination without duplicates you can do this with the following. The test to find duplicates is just to confirm it doesn't generate any duplicates in the first place.
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String... args) {
Bag<Integer> b = new Bag<>();
b.countFor(1, 2);
b.countFor(2, 1);
b.countFor(3, 3);
Set<String> set = new LinkedHashSet<>();
for (List<Integer> list : b.combinations()) {
System.out.println(list);
String s = list.toString();
if (!set.add(s))
System.err.println("Duplicate entry " + s);
}
}
}
class Bag<E> {
final Map<E, AtomicInteger> countMap = new LinkedHashMap<>();
void countFor(E e, int n) {
countMap.put(e, new AtomicInteger(n));
}
void decrement(E e) {
AtomicInteger ai = countMap.get(e);
if (ai.decrementAndGet() < 1)
countMap.remove(e);
}
void increment(E e) {
AtomicInteger ai = countMap.get(e);
if (ai == null)
countMap.put(e, new AtomicInteger(1));
else
ai.incrementAndGet();
}
List<List<E>> combinations() {
List<List<E>> ret = new ArrayList<>();
List<E> current = new ArrayList<>();
combinations0(ret, current);
return ret;
}
private void combinations0(List<List<E>> ret, List<E> current) {
if (countMap.isEmpty()) {
ret.add(new ArrayList<E>(current));
return;
}
int position = current.size();
current.add(null);
List<E> es = new ArrayList<>(countMap.keySet());
if (es.get(0) instanceof Comparable)
Collections.sort((List) es);
for (E e : es) {
current.set(position, e);
decrement(e);
combinations0(ret, current);
increment(e);
}
current.remove(position);
}
}

Categories

Resources