I came across a problem where one needs to check for rows in Array1 that are not in Array2 and append it at the end of Array2 in Java. The rows that are common with regard to the first column i.e. name can be skipped. In the below example, the rows in firstarray with "Nick" and "Bruce" should be appended at the end of secondarray.
I have edited the arrays again slightly to get more clarity.
String firstarray[][] = {
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","New York"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
The solution should be like:
secondarray[][]:
{"Adam","01-Dec-1980","Commerce","New York"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}}
Collect the names of the second array to a set, iterate over your first array and filter out those elements which are in the set and collect the result in a third array (or any other collection). Append this collection to your second array.
public static void main(String[] args){
String firstarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Sujay Muramalla","08-Jan-1985","Arts","London"}};
//collect names of second array to set
Set<String> secondSet = Arrays.stream(secondarray).map(e -> e[0]).collect(Collectors.toSet());
//stream over your first array and keep only those which are not in the above set
String[][] third = Arrays.stream(firstarray)
.filter(e -> !secondSet.contains(e[0]))
.toArray(String[][]::new);
//stream over second and delta (third array) and collect to a result array
String[][] result = Stream.concat(Arrays.stream(secondarray), Arrays.stream(third))
.toArray(String[][]::new);
//output
Arrays.stream(result).forEach(e ->{
System.out.println(Arrays.toString(e));
});
}
You should not be using arrays for this. Much better to use libraries already doing the job.
Even if the data you receive is already that way, you can converted first to a Map<String, Person> it will be more efficient, and readable code.
With arrays or many solutions not using some hashing system, you end up with exponential complexity O(n2), so not efficient.
Convert at least secondarray
Map<String, Person> secondMap = new HashMap();
for(String [] row : secondarray){
secondMap.put(row[0], new Person(row[0], row[1], row[2], row[3]));
}
Then put in the map if not already there
for(String[] row : firstarray){
if(!secondMap.containsKey(row[0])){
secondMap.put(row[0], new Person(row[0], row[1], row[2], row[3]));
}
}
Where Person class could be simply defined as
private static class Person{
public Person(String name, String birth, String area, String city){
this.name = name;
this.birth = birth;
this.area = area;
this.city = city;
}
String name;
String birth;
String area;
String city;
}
if you want check more than the first element of the array you can use nopens solution and replace e[0] with Arrays.toString(e).
A cleaner way if this is possible for you, is to use a list with a object and use a id for checking equals or override the hashcode function of the customer object.
You can also check for name and birth like that:
class Customer {
private String name;
private String birth;
private String type;
private String location;
public Customer(String name, String birth, String type, String location) {
this.name = name;
this.birth = birth;
this.type = type;
this.location = location;
}
#Override
public String toString() {
return "Customer [name=" + name + ", birth=" + birth + ", type=" + type + ", location=" + location + "]";
}
}
List<Customer> firstList = new ArrayList<Customer>();
firstList.add(new Customer("Adam", "01-Dec-1980", "Commerce", "Kansas"));
firstList.add(new Customer("John", "04-Feb-1982", "Economics", "Leeds"));
firstList.add(new Customer("Mathias", "08-Jan-1985", "Arts", "London"));
firstList.add(new Customer("Nick", "09-06-1974", "History", "Johanesburg"));
firstList.add(new Customer("Bruce", "13-08-1975", "Philosophy", "Seattle"));
List<Customer> secondList = new ArrayList<Customer>();
secondList.add(new Customer("Adam", "01-Dec-1980", "Commerce", "Kansas"));
secondList.add(new Customer("John", "04-Feb-1982", "Economics", "Leeds"));
secondList.add(new Customer("Mathias", "08-Jan-1985", "Arts", "London"));
for (Customer customer : firstList) {
if (containsNameAndBirth(secondList, customer) == false) {
secondList.add(customer);
}
}
for (Customer customer : secondList) {
System.out.println(customer);
}
}
public static boolean containsNameAndBirth(final List<Customer> list, final Customer customer) {
return list.stream().filter(o -> o.name.equals(customer.name) && o.birth.equals(customer.birth)).findFirst()
.isPresent();
}
EDIT 1 - Using Custom Class
I suggest you to always use List over Array.
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;
public class Main {
static class Person {
public String name;
public String birthDate;
public String field;
public String city;
public static Person fromArray(String[] data) {
Person p = new Person();
if (data.length == 4) {
p.name = data[0];
p.birthDate = data[1];
p.field = data[2];
p.city = data[3];
} else {
// Handle me
}
return p;
}
#Override
public String toString() {
return new StringBuilder("[").append(name)
.append(",").append(birthDate)
.append("] learns ").append(field)
.append(" at ").append(city).toString();
}
}
public static void main(String[] args) {
String firstArray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondArray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
List<Person> finalList = getFinalList(firstArray, secondArray);
// Display
System.out.println(finalList);
}
public static List<Person> getFinalList(String[][] arr1, String[][] arr2) {
// First cast to Lists of persons
List<Person> firstList = Arrays.asList(arr1).stream().map(Person::fromArray).collect(Collectors.toList());
List<Person> secondList = Arrays.asList(arr2).stream().map(Person::fromArray).collect(Collectors.toList());
// Get names in secondList
Set<String> existingNames = secondList.stream().map(p -> p.name).collect(Collectors.toSet());
System.out.println("Names: "+ existingNames);
firstList.forEach(person -> {
if (! existingNames.contains(person.name)) {
secondList.add(person);
}
});
return secondList;
}
}
I upvoted nopens solutions cause it is nice one
Here another that uses maps and makes use of a logic of skipping common keys using removeAll on the keySet of the map, which was a functional method existing befor Java turned "more" functional
static public <T> Map<T,T[]> arrayToMap(T[][] array, int i) {
return Arrays.stream(array).collect(Collectors.toMap(e -> e[i], e -> e));
}
public static void main(String[] args){
String firstarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Sujay Muramalla","08-Jan-1985","Arts","London"}};
Map<String,String[]> firstMap = arrayToMap(firstarray, 0);
Map<String,String[]> secondMap = arrayToMap(secondarray, 0);
secondMap.keySet().removeAll(firstMap.keySet());
firstMap.putAll(secondMap);
String[][] result = firstMap.values().stream().toArray(String[][]::new);
//output
Arrays.stream(result).forEach(e ->{
System.out.println(Arrays.toString(e));
});
}
sidenote: in arrayToMap you can choose which column you use as key.
And the logic could be even reduced to this 3 lines:
Map<String,String[]> firstMap = arrayToMap(firstarray, 0);
firstMap.putAll(arrayToMap(secondarray, 0));
String[][] result = firstMap.values().stream().toArray(String[][]::new);
since inserting a value with the same key overwrites the existing one and you get the same if the values are the same in case of equal keys.
A simple an efficient way to do it (if you don't care about ordering) is the following:
Time complexity: O(nlog(n))
Space complexity: O(n+m)
import java.util.Arrays;
public class Main {
public static void main(String ... args) {
String firstarray[][] = {
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"},
{"Nick","09-06-1974","History","Johanesburg"},
{"Bruce","13-08-1975","Philosophy","Seattle"}};
String secondarray[][] = {
{"Adam","01-Dec-1980","Commerce","Kansas"},
{"John","04-Feb-1982","Economics","Leeds"},
{"Mathias","08-Jan-1985","Arts","London"}};
String result [][] = new String[firstarray.length
+ secondarray.length][firstarray[0].length];
// sort firstarray
java.util.Arrays.sort(firstarray, new java.util.Comparator<String[]>() {
public int compare(String [] a, String[] b) {
return a[0].compareTo(b[0]);
}
});
//sort secondarray
java.util.Arrays.sort(secondarray, new java.util.Comparator<String[]>() {
public int compare(String [] a, String[] b) {
return a[0].compareTo(b[0]);
}
});
int i = 0, j=0, k=0, cmp ;
for ( ;i < secondarray.length && j< firstarray.length;) {
cmp = firstarray[i][0].compareTo(secondarray[j][0]);
if(cmp ==0) {
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
i++; j++;
}else if( cmp <0){
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
i++;
} else {
System.arraycopy(secondarray[j], 0, result[k++], 0, 4);
j++;
}
}
// copy the remaining if any from firstarray to the result
for (; i < firstarray.length; i++) {
System.arraycopy(firstarray[i], 0, result[k++], 0, 4);
}
// copy the remaining if any from secondarray to the result
for (; j < secondarray.length; j++) {
System.arraycopy(secondarray[j], 0, result[k++], 0, 4);
}
//resize it
secondarray = Arrays.copyOf(result, k);
// just print the secondarray
for (int x = 0; x < secondarray.length; x++) {
for (int y = 0; y < 4; y++) {
System.out.print(secondarray[x][y] + ",");
}
System.out.println("");
}
}
}
I have created a program that sorts trading cards and places them in a collection that is then compared to other collections to look for duplicates. I have had no problems up until my final toString method. My issue is that I cannot seem to get the return statement to separate the various cards onto their own separate lines.
instead of Alan Turing, Grace Hopper, Ada Lovelace, I need:
Alan Turing
Grace Hopper
Ada Lovelace
Below is a copy of my code. I am fairly new to java so I apologize for any lack of knowledge pertaining to methods specific to this, but I have only found ones using System.out.println, and not mentioning return in any way. My problem lies in the method defined by **. I appreciate any and all help and am sorry if this question is not 100% clear. (I have tried my own research to no avail!)
// First Class
public class Card implements Comparable<Card> {
private String name;
private String nationality;
private int yearBorn;
private int yearDied;
public Card(String name, String nationality, int yearBorn, int yearDied) {
this.name=name;
this.nationality=nationality;
this.yearBorn=yearBorn;
this.yearDied=yearDied;
}
public int compareTo(Card c) {
if (this.name.equals(c.name)) return 0;
else if (this.name.compareTo(c.name)>0) return 1;
else return -1;
}
public String toString() {
return String.format("%s (%d - %d) - %s", name, yearBorn, yearDied, nationality);
}
}
// Second Class
import java.util.ArrayList;
import java.util.List;
public class CardCollection {
private String owner;
private List<Card> myCollection;
public CardCollection(String owner) {
this.owner = owner;
this.myCollection = new ArrayList<>();
}
public boolean addCard(Card c) {
int p = 0;
while (p < myCollection.size()) {
int q = myCollection.get(p).compareTo(c);
if (q == 0) {
return false;
} else if (q > 0) {
myCollection.add(p, c);
return true;
}
p++;
}
myCollection.add(c);
return true;
}
public void removeCard(int r) {
myCollection.remove(r);
}
public int getSize() {
return myCollection.size();
}
public ArrayList<Card> mergeCollections(CardCollection cc) {
ArrayList<Card> dupes = new ArrayList<>();
while (cc.getSize() > 0) {
Card c = cc.myCollection.remove(0);
if (myCollection.contains(c)) {
dupes.add(c);
}
else myCollection.add(c);
}
return dupes;
}
**public String toString() {
String s = "";
for (int i = 0; i < owner.length(); i++) {
s += "-";
}
return String.format("%s\n%s\n%s\n", owner, s, myCollection);**
}
}
// Runner Class
import java.util.ArrayList;
public class CCRunner {
public static void main(String[] args) {
CardCollection c1 = new CardCollection("Alan");
CardCollection c2 = new CardCollection("Grace");
Card turing = new Card("Alan Turing","British",1912,1954);
Card hopper = new Card("Grace Hopper","American",1906,1992);
Card vonneumann = new Card("John Von Neumann","Hungarian",1903,1957);
Card shannon = new Card("Claude Shannon","American",1916,2001);
Card johnson = new Card("Katherine Johnson","American",1918,-1);
Card lovelace = new Card("Ada Lovelace","British",1815,1852);
Card cerf = new Card("Vint Cerf","American",1943,-1);
Card brin = new Card("Sergey Brin","Russian",1973,-1);
c1.addCard(turing);
c1.addCard(vonneumann);
c1.addCard(shannon);
c1.addCard(johnson);
c1.addCard(cerf);
c1.addCard(brin);
c2.addCard(cerf);
c2.addCard(lovelace);
c2.addCard(johnson);
c2.addCard(vonneumann);
c2.addCard(hopper);
System.out.println(c1);
System.out.println(c2);
ArrayList<Card> dupes = c1.mergeCollections(c2);
System.out.println(c1);
System.out.println(c2);
System.out.println("Duplicates:\n-----------");
for (Card c : dupes) {
System.out.println(c);
}
}
}
This is run in a separate class, but I don't think it will elucidate my problem to include it. Let me know if I am wrong.
You can either change your implementation of toString() of your CardCollection class. Examples:
Loop again, this time over the List:
public final String toString() {
String s = "";
for (int i = 0; i < owner.length(); i++) {
s += "-";
}
for (int i = 0; i < myCollection.size(); i++) {
s += "\n" + myCollection.get(i);
}
return String.format("%s\n%s\n", owner, s);
}
Using a stream (requires an additional import java.util.stream.Collectors;):
public final String toString() {
String s = "";
for (int i = 0; i < owner.length(); i++) {
s += "-";
}
return String.format("%s\n%s\n%s\n",
owner,
s,
myCollection.stream()
.map(Card::toString)
.collect(Collectors.joining("\n")));
}
Or you can #Override the toString() method of the ArrayList, also in your CardCollection class. Example:
this.myCollection = new ArrayList<>(){
#Override
public String toString(){
String s = "";
if (size() > 0) s = get(0).toString();
for (int i = 1; i < size(); i++) {
s += "\n" + get(i).toString();
}
return s;
}
};
All examples will result in this for Alan (before the merge):
Alan
----
Alan Turing (1912 - 1954) - British
Claude Shannon (1916 - 2001) - American
John Von Neumann (1903 - 1957) - Hungarian
Katherine Johnson (1918 - -1) - American
Sergey Brin (1973 - -1) - Russian
Vint Cerf (1943 - -1) - American
Note: I'd personally go with changing the implementation of toString() of the CardCollection class. I would also perfer the way tquadrat did it in their answer. The overriding of ArrayList looks to messy in my opinion, and keeping the stringrepresentation in the toString() method makes more sense to me.
Try this as a replacement to the marked toString() implementation:
…
public final String toString()
{
var s = "-".repeat( owner.length() );
var joiner = new StringJoiner( "\n", String.format( "%s%n%s%n", owner, s ), "" );
for( var c : myCollection ) joiner.add( c.toString() );
var retValue = joiner.toString();
return retValue;
}
Basically, the output would look like this:
<owner>
-------
<collectible1>
<collectible2>
<…>
If you are using a Java version before Java 11, you may need to replace var with the respective types.
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;
}
}
This is my first time to write a bubble sort for string and apparently i got many errors and the program could not run. I have no idea how to solve it. my code is:
import java.util.*;
public class SortingRecord{
public static void main(String args[]){
Scanner kb = new Scanner(System.in);
System.out.println("How many people?");
int n = Integer.parseInt(kb.nextLine());
Record[] records = new Record[n];
for(int i = 0; i<n; i++){
System.out.println("Inputting record["+i+"]:");
System.out.print("Please input <First Name>:");
String firstName = kb.nextLine();
System.out.println("Please input <Last Name>:");
String lastName = kb.nextLine();
records[i] = new Record(firstName, lastName);
}
sort(records);
System.out.println("----------------");
System.out.println("Print name in dictinary order:");
for(int i = 0; i < n ; i++)
System.out.println();
}
public static void sort(Record[] records){
if (records == null || records.length <= 1) return;
int n = records.length;
for(int i = 0; i< records.length ; i++){
for(int j = i+1 ; j< records.length; j++){
The symbol method compareTo(Record) couldn't be found.
if(records[j] .compareTo(records[i]) < 0){
It said Record cannot be converted to java.lang.String
String temp = records[i];
records[i] = records[j];
records[j] = temp;
}
}
System.out.println(records[i]);
}
}
}
class Record{
public String firstName = "";
public String lastName = "";
public Record(String firstName, String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
}
Let's take a look at the obvious error:
if (records[j].compareTo(records[i]) < 0) {
Record does not provide any compareTo method, so you can't call it - it doesn't exist.
The next error:
String temp = records[i];
Is because Record is not a type of String, so it can't be assigned, the obvious solution is to use Record instead, something like...
Record temp = records[i];
records[i] = records[j];
records[j] = temp;
Okay, but how do we fix the compareTo issue? This is more complicated than it might sound, while you implement the Comparable interface (or just implement the compareTo method directly), I'd not choose this path. Why? Because you might want to change the way in which you sort the records and implementing the method would lock you into a single use case.
Instead, I'd use a Comparator passed into the method to do the actual comparison, providing the caller with the flexibility to change how the comparison actually works
public static void sort(Record[] records, Comparator<Record> comparator) {
if (records == null || records.length <= 1) {
return;
}
int n = records.length;
for (int i = 0; i < records.length; i++) {
for (int j = i + 1; j < records.length; j++) {
if (comparator.compare(records[j], records[i]) < 0) {
Record temp = records[i];
records[i] = records[j];
records[j] = temp;
}
}
System.out.println(records[i]);
}
}
Then you could do something like...
sort(records, new Comparator<Record>() {
#Override
public int compare(Record o1, Record o2) {
return o1.firstName.compareTo(o2.firstName);
}
});
or
sort(records, new Comparator<Record>() {
#Override
public int compare(Record o1, Record o2) {
return o1.lastName.compareTo(o2.lastName);
}
});
or even
sort(records, new Comparator<Record>() {
#Override
public int compare(Record o1, Record o2) {
int compare = o1.firstName.compareTo(o2.firstName);
if (compare == 0) {
compare = o1.lastName.compareTo(o2.lastName);
}
return compare;
}
});
Or what ever else combination you might need to meet your requirements
I would suggest having a look at Comparator for more details
I should also point out that you could use Collections to also so the objects, but you'll need to convert it to List instead of array...
Collections.sort(Arrays.asList(records), new Comparator<Record>() {...});
the program fail to output the name in dictionary order;(
Works fine for me...
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
Record[] records = new Record[] {
new Record("B", "B"),
new Record("C", "B"),
new Record("D", "B"),
new Record("A", "E"),
new Record("A", "B"),
new Record("A", "C"),
new Record("A", "A"),
};
sort(records, new Comparator<Record>() {
#Override
public int compare(Record o1, Record o2) {
int compare = o1.firstName.compareTo(o2.firstName);
if (compare == 0) {
compare = o1.lastName.compareTo(o2.lastName);
}
return compare;
}
});
for (Record record : records) {
System.out.println(record);
}
}
public static void sort(Record[] records, Comparator<Record> comparator) {
if (records == null || records.length <= 1) {
return;
}
for (int i = 0; i < records.length; i++) {
for (int j = i + 1; j < records.length; j++) {
if (comparator.compare(records[j], records[i]) < 0) {
Record temp = records[i];
records[i] = records[j];
records[j] = temp;
}
}
}
}
class Record {
public String firstName = "";
public String lastName = "";
public Record(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return firstName + " " + lastName;
}
}
}
Outputs
A A
A B
A C
A E
B B
C B
D B
You don't have compareTo method in Record class so that's why it's not found :) You probably should implement Comparable interface.
As to "Record cannot be converted to java.lang.String", use toString method and you will be able to convert it, although you probably want to override toString.
Please also take a look at this example:
Why should a Java class implement comparable?
There are lots of components out there creating/parsing barcode images but i could not manage to find a library which parses a EAN-128 barcode-string and gives me simply a java-pojo object from which I can get EAN-128 groups if they were included in the barcode.
Example pseudocode:
EAN128Pojo pojo = EAN128Pojo.parse(some string got from scanner);
Date dueDate = pojo.getDueDate();
or
Object dueDate = pojo.get("12" /*application identifier for due date*/);
Is there any library capable of this?
I don't know of any, and neither does Google CodeSearch: http://www.google.com/codesearch?q=getAdditionalProductIdentification
Anyway, writing your own isn't that difficult. This one took me less than an hour:
package so5685964;
import java.util.Map;
import org.joda.time.DateMidnight;
import com.google.common.collect.Maps;
public class GS1Code128Data {
/** Maps the AI to the corresponding data from the barcode. */
private final Map<String, String> data = Maps.newHashMap();
private static final Map<String, AII> aiinfo = Maps.newHashMap();
static class AII {
final int minLength;
final int maxLength;
public AII(String id, int minLength, int maxLength) {
this.minLength = minLength;
this.maxLength = maxLength;
}
}
private static void ai(String id, int minLength, int maxLength) {
aiinfo.put(id, new AII(id, minLength, maxLength));
}
private static void ai(String id, int length) {
aiinfo.put(id, new AII(id, length, length));
}
static {
ai("00", 18, 18);
ai("01", 14);
ai("02", 14);
ai("10", 1, 20);
ai("11", 6);
ai("12", 6);
// TODO: continue according to http://en.wikipedia.org/wiki/GS1-128
}
/**
* Decodes a Unicode string from a Code128-like encoding.
*
* #param fnc1 The character that represents FNC1.
*/
public GS1Code128Data(String s, char fnc1) {
StringBuilder ai = new StringBuilder();
int index = 0;
while (index < s.length()) {
ai.append(s.charAt(index++));
AII info = aiinfo.get(ai.toString());
if (info != null) {
StringBuilder value = new StringBuilder();
for (int i = 0; i < info.maxLength && index < s.length(); i++) {
char c = s.charAt(index++);
if (c == fnc1) {
break;
}
value.append(c);
}
if (value.length() < info.minLength) {
throw new IllegalArgumentException("Short field for AI \"" + ai + "\": \"" + value + "\".");
}
data.put(ai.toString(), value.toString());
ai.setLength(0);
}
}
if (ai.length() > 0) {
throw new IllegalArgumentException("Unknown AI \"" + ai + "\".");
}
}
private static DateMidnight asDate(String s) {
if (s == null) {
return null;
}
String century = s.compareTo("500000") < 0 ? "20" : "19";
return new DateMidnight(century + s);
}
public DateMidnight getDueDate() {
return asDate(data.get("12"));
}
}
And some demonstration code:
package so5685964;
public class BarcodeDemo {
public static void main(String[] args) {
String barcode = "12110416";
GS1Code128Data data = new GS1Code128Data(barcode, '\f');
System.out.println(data.getDueDate());
}
}
When you assume that your input is already a String, pay attention to encoding issues. The FNC1 code does not have a corresponding Unicode Code Point, so it has to be encoded in some other way.
The GS1 Barcode Syntax Engine is a native library with a Java binding that is purpose built for processing GS1 Application Identifier syntax.
https://github.com/gs1/gs1-syntax-engine