Add to a String[] another String[] - java

Info = new String[15];
Livraison = new String[5];
Facturation = new String[5];
Autres = new String[3];
Livraison = AddressForm(JP_Add_Livraison,"Livraison");
Facturation = AddressForm(JP_Add_Facturation,"Facturation");
Autres[0] = JT_Tel.getText();
Autres[1] = JT_Contact.getText();
Autres[2] = JT_Date.getText();
Autres[3] = JT_Note.getText();
Info.add(Livraison);
Info.add(Facturation);
Info.add(Autres);
I want the 3 String[] -> Livraison + Facturation + Autres in Info[]
How can I do that ?
Thanks

You'll find it much easier to do this if you work with the standard collections types. In particular, try using List<String>, instead of String[]. Then you'll find that adding mutiple lists to another list is a simple matter of calling the "addAll" method which is designed to copy the elements from one collection to another.

You can create and array of arrays like this:
String[][] arrays = { array1, array2, array3, array4, array5 };
But, alternatively, you could create a class that has those attributes, don't know if that's what you want to do..
public class Something{
String[] Livraison;
String[] Facturation;
String[] Autres;
}

Arrays.copyOf will work for you.
A suggestion - how to do this!
int len1 = newarray.length;
int len2 = arraytobecopied.length;
String[] result = Arrays.copyOf(newarray, len1 + len2);
System.arraycopy(arraytobecopied, 0, result, len1, len2);

public static void main(String[] args) throws Exception {
String[] all = new String[15];
String[] some = new String[] { "one", "two", "three" };
String[] more = new String[] { "four", "five" };
System.arraycopy(some, 0, all, 0, some.length);
System.arraycopy(more, 0, all, some.length, more.length);
for (String value : all) System.out.println(value);
}

Totally over the top unless you need to do this a lot (I do) you may find wrapping the arrays in an Iterable useful.
public class JoinedArray<T> implements Iterable<T> {
final List<T[]> joined;
#SafeVarargs
public JoinedArray(T[]... arrays) {
joined = Arrays.<T[]>asList(arrays);
}
#Override
public Iterator<T> iterator() {
return new JoinedIterator<>(joined);
}
private class JoinedIterator<T> implements Iterator<T> {
// The iterator acrioss the arrays.
Iterator<T[]> i;
// The array I am working on.
T[] a;
// Where we are in it.
int ai;
// The next T to return.
T next = null;
private JoinedIterator(List<T[]> joined) {
i = joined.iterator();
a = i.hasNext() ? i.next() : null;
ai = 0;
}
#Override
public boolean hasNext() {
if (next == null) {
// a goes to null at the end of i.
if (a != null) {
// End of a?
if (ai >= a.length) {
// Yes! Next i.
if (i.hasNext()) {
a = i.next();
} else {
// Finished.
a = null;
}
ai = 0;
}
if (a != null) {
next = a[ai++];
}
}
}
return next != null;
}
#Override
public T next() {
T n = null;
if (hasNext()) {
// Give it to them.
n = next;
next = null;
} else {
// Not there!!
throw new NoSuchElementException();
}
return n;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
}
public int copyTo(T[] to, int offset, int length) {
int copied = 0;
// Walk each of my arrays.
for (T[] a : joined) {
// All done if nothing left to copy.
if (length <= 0) {
break;
}
if (offset < a.length) {
// Copy up to the end or to the limit, whichever is the first.
int n = Math.min(a.length - offset, length);
System.arraycopy(a, offset, to, copied, n);
offset = 0;
copied += n;
length -= n;
} else {
// Skip this array completely.
offset -= a.length;
}
}
return copied;
}
public int copyTo(T[] to, int offset) {
return copyTo(to, offset, to.length);
}
public int copyTo(T[] to) {
return copyTo(to, 0);
}
#Override
public String toString() {
StringBuilder s = new StringBuilder();
Separator comma = new Separator(",");
for (T[] a : joined) {
s.append(comma.sep()).append(Arrays.toString(a));
}
return s.toString();
}
public static void main(String[] args) {
JoinedArray<String> a = new JoinedArray<>(
new String[]{
"One"
},
new String[]{
"Two",
"Three",
"Four",
"Five"
},
new String[]{
"Six",
"Seven",
"Eight",
"Nine"
});
for (String s : a) {
System.out.println(s);
}
String[] four = new String[4];
int copied = a.copyTo(four, 3, 4);
System.out.println("Copied " + copied + " = " + Arrays.toString(four));
}
}
Note that the arrays are used to back the lists internally so if you change the arrays the joined versions also change. Obviously if the arrays get resized then that will break the connection.

ask yourself question : do i really need arrays?
based on your code sample:(which actually shoulnd work as you declare length of Autres 3 and add 4 elements)
Autres[0] = JT_Tel.getText();
Autres[1] = JT_Contact.getText();
Autres[2] = JT_Date.getText();
Autres[3] = JT_Note.getText();
i recommend you to go with object Autres
class Autres{
private String tel,contact,date,note;
//getters and setters ommited
}

Related

How to order a matrix of object

I'm working on an application that read a file Excel with Apache POI. I put the cells value inside a matrix of String object.
[title 1][title 2][title 3]
[mark] [smith] [34]
[simon] [black] [24]
I've been ask to allow to order the matrix according to the selected column.
How can I order a matrix of String object?
Thank you
If you have only few columns you can create some comparators with a meaningful name and sort like below:
public static void main(String[] args) {
String[][] matrix = {{"mark","smith","34"},
{"simon","black","24"},
{"foo","bar","44"}
};
Comparator<String[]> firstNameComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return row1[0].compareTo(row2[0]);
}
};
Comparator<String[]> lastNameComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return row1[1].compareTo(row2[1]);
}
};
Comparator<String[]> ageComparator = new Comparator<String[]>() {
#Override
public int compare(String[] row1, String[] row2) {
return Integer.compare(Integer.parseInt(row1[2]), Integer.parseInt(row2[2]));
}
};
Arrays.sort(matrix, firstNameComparator);// pass the desired comparator
for(String[] row:matrix){
System.out.println(Arrays.toString(row));
}
}
or create a class that extends Comparator and pass the column index:
public class NewClass5 {
public static void main(String[] args) {
String[][] matrix = {{"mark","smith","34"},
{"simon","black","24"},
{"foo","bar","44"}
};
Arrays.sort(matrix, new CompareByColumn(1));// pass the desired index
for(String[] row:matrix){
System.out.println(Arrays.toString(row));
}
}
static class CompareByColumn implements Comparator {
int columnToSort;
CompareByColumn(int columnToSort) {
this.columnToSort = columnToSort;
}
public int compare(Object o1, Object o2) {
String[] row1 = (String[]) o1;
String[] row2 = (String[]) o2;
return row1[columnToSort].compareTo(row2[columnToSort]);
}
}
}
With java 8 and streams you can write it even more compactly:
String[][] sorted = Arrays.stream(matrix)
.sorted((s1,s2)->s1[1].compareTo(s2[1])) // pass the desired index
.toArray(String[][]::new);
for(String[] row: sorted){
System.out.println(Arrays.toString(row));
}
EDIT
Since you prefer the stream approach, I have only reworked this one. But you can use it for the other approaches as well. You can check before the comparison if the corresponding column contains numbers and make your comparison in a simple if-else either for numbers or strings.
int colIndex = 2;
String[][] sorted = Arrays.stream(matrix).sorted((s1,s2)-> {
if(s1[colIndex].matches("(\\d+(?:\\.\\d+)?)")){
return Double.compare(Double.parseDouble(s1[colIndex]), Double.parseDouble(s2[colIndex]));
}
else{
return s1[2].compareTo(s2[2]);
}})
.toArray(String[][]::new);
for(String[] row: sorted){
System.out.println(Arrays.toString(row));
}
Used this (\d+(?:\.\d+)?) regex to match both integer and floating point numbers.
First of all thank you for this question, it proved to be quite a mental challenge to visualize and implement this solution. I hope the following solution is what you wanted.
I've written a method that will sort the matrix for you. The method takes a String matrix as an argument and returns a new String matrix with each column sorted by alphabetic older. The sorting is done independent of other columns so each column is sorted without external context.
Unfortunately it doesn't exclude the titles from the sorting process so if you need that to happen please let me know and I will do my best to implement that.
public static boolean isNumeric(String str) {
return str.matches("^[0-9]+$");
}
public static String[][] sortMatrix(String[][] matrix)
{
int matrixLength = matrix[0].length;
String[][] sortedMatrix = new String[matrixLength][];
java.util.List<String[]> columns = new java.util.ArrayList<>();
for (int i1 = 0; i1 < matrixLength; i1++)
{
String[] column = new String[matrixLength];
for (int i2 = 0; i2 < matrixLength; i2++) {
column[i2] = matrix[i2][i1];
}
columns.add(column);
}
// First sort the column before proceeding
columns.forEach(column -> Arrays.sort(column, new Comparator<String>()
{
public int compare(String s1, String s2)
{
boolean i1 = isNumeric(s1);
boolean i2 = isNumeric(s2);
if (i1 && i2) {
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
else if (!i1) {
return 1;
}
else return -1;
}
}));
for (int i1 = 0; i1 < columns.size(); i1++)
{
String[] row = new String[matrixLength];
for (int i2 = 0; i2 < matrixLength; i2++) {
row[i2] = columns.get(i2)[i1];
}
sortedMatrix[i1] = row;
}
return sortedMatrix;
}
public static void main(String[] args) throws IOException {
String[][] matrix = new String[3][] ;
matrix[0] = new String[] { "title 1", "title 2", "title 3" };
matrix[1] = new String[] { "simon", "1", "10" };
matrix[2] = new String[] { "mark", "35", "2" };
matrix = sortMatrix(matrix);
for (String[] row : matrix) {
System.out.println(Arrays.toString(row));
}
}
EDIT: Implemented a custom comparator that takes number into account.

how to return equivalent Arrays

A function named equivalentArrays that has two array arguments and returns 1 if the two arrays contain the same values (but not necessarily in the same order), otherwise it returns 0. Note that the arrays do not have to have the same number of elements, they just have to have one of more copies of the same values.
public class Equavalenarray {
public static void main(String[] args) {
int result= equivalentArrays(new int[] {}, new int[] {});
System.out.println(result);
result=equivalentArrays (new int [] {0,2,1,2}, new int [] {0,2,1,2,1});
System.out.println(result);
result=equivalentArrays (new int [] {3,1,2,0}, new int [] {0,2,1,0});
System.out.println(result);
}
public static int equivalentArrays(int[ ] a1, int[ ] a2) {
if(a1==null || a2==null) return 0;
for(int i=0; i<a1.length; i++) {
for(int j=0; j<a2.length; j++) {
if(a1[i]==a2[j] )
{
return 1;
}
}
}
return 0;
}
}
You're almost there with your function. To finish, we'll need to do some workarounds here.
You can check each value within the smaller array and remove the compared value in the bigger array (in case of repeated values).
if in some comparison they're different, it returns 0. If it reach the end of smaller array, they are equals.
Replace your for loops by this snippet:
// converted the values to ArrayList to remove values easily.
// PS: to convert them to ArrayList, the array types must of the Integer
List<Integer> l1 = new ArrayList<Integer>(Arrays.asList(a1.length <= a2.length ? a1 : a2)); // to save in l1 the smaller array
List<Integer> l2 = new ArrayList<Integer>(Arrays.asList(a2.length >= a1.length ? a2 : a1)); // to save in l2 the bigger array
for(int i=0; i<l1.size(); i++) {
if(!l2.contains(l1.get(i)))
return 0;
else
l2.remove(l2.indexOf(l1.get(i)));
}
return 1;
Updated live example here.
public class Equavalenarray {
public static void main(String[] args) {
System.out.println(equivalentArrays(new int[]{0,1,2}, new int[]{2,0,1}));
System.out.println(equivalentArrays(new int[]{0,1,2,1}, new int[]{2,0,1}));
System.out.println(equivalentArrays( new int[]{2,0,1}, new int[]{0,1,2,1}));
System.out.println(equivalentArrays( new int[]{0,5,5,5,1,2,1}, new int[]{5,2,0,1}));
System.out.println(equivalentArrays( new int[]{5,2,0,1}, new int[]{0,5,5,5,1,2,1}));
System.out.println(equivalentArrays( new int[]{0,2,1,2}, new int[]{3,1,2,0}));
System.out.println(equivalentArrays( new int[]{3,1,2,0}, new int[]{0,2,1,2}));
System.out.println(equivalentArrays( new int[]{1,1,1,1,1,1}, new int[]{1,1,1,1,1,2}));
System.out.println(equivalentArrays( new int[]{ }, new int[]{3,1,1,1,1,2}));
System.out.println(equivalentArrays( new int[]{ }, new int[]{ }));
}
public static int equivalentArrays(int[] a1, int[] a2) {
if(a1==null && a2==null) return 0;
boolean found;
for(int i : a1) {
found = false;
for(int j : a2) {
if(i==j) {
found = true;
break;
}
}
if(found==false) {
return 0;
}
}
for(int i : a2) {
found = false;
for(int j : a1) {
if(i==j) {
found = true;
break;
}
}
if(found==false) {
return 0;
}
}
return 1;
}
}
}

Constraining all combinations of an array-list

I know similar questions have been asked before but I have found the answers confusing. I am trying to make a program that will find every combination of an array-list with no repetitions and only of the maximum size. If the list has 4 items it should print out only the combinations with all 4 items present. This is what I have so far:
public main(){
UI.initialise();
UI.addButton("Test", this::testCreate);
UI.addButton("Quit", UI::quit);
}
public void createCombinations(ArrayList<String> list, String s, int depth) {
if (depth == 0) {
return;
}
depth --;
for (int i = 0; i < list.size(); i++) {
if (this.constrain(s + "_" + list.get(i), list.size())) {
UI.println(s + "_" + list.get(i));
}
createCombinations(list, s + "_" + list.get(i), depth);
}
}
public void testCreate() {
ArrayList<String> n = new ArrayList<String>();
n.add("A"); n.add("B"); n.add("C"); n.add("D");
this.createCombinations(n , "", n.size());
}
public boolean constrain(String s, int size) {
// Constrain to only the maximum length
if ((s.length() != size*2)) {
return false;
}
// Constrain to only combinations without repeats
Scanner scan = new Scanner(s).useDelimiter("_");
ArrayList<String> usedTokens = new ArrayList<String>();
String token;
while (scan.hasNext()) {
token = scan.next();
if (usedTokens.contains(token)) {
return false;
} else {
usedTokens.add(token);
}
}
// If we fully iterate over the loop then there are no repitions
return true;
}
public static void main(String[] args){
main obj = new main();
}
This prints out the following which is correct:
_A_B_C_D
_A_B_D_C
_A_C_B_D
_A_C_D_B
_A_D_B_C
_A_D_C_B
_B_A_C_D
_B_A_D_C
_B_C_A_D
_B_C_D_A
_B_D_A_C
_B_D_C_A
_C_A_B_D
_C_A_D_B
_C_B_A_D
_C_B_D_A
_C_D_A_B
_C_D_B_A
_D_A_B_C
_D_A_C_B
_D_B_A_C
_D_B_C_A
_D_C_A_B
_D_C_B_A
This works for small lists but is very inefficient for larger ones. I am aware that what I have done is completely wrong but I want to learn the correct way. Any help is really appreciated. Thanks in advance.
P.S. This is not homework, just for interest although I am a new CS student (if it wasn't obvious).
Implementing Heap's algorithm in Java:
import java.util.Arrays;
public class Main {
public static void swap(final Object[] array, final int index1, final int index2) {
final Object tmp = array[index1];
array[index1] = array[index2];
array[index2] = tmp;
}
public static void printPermutations_HeapsAlgorithm(final int n, final Object[] array) {
final int[] c = new int[n];
for (int i = 0; i < c.length; ++i)
c[i] = 0;
System.out.println(Arrays.toString(array)); //Consume first permutation.
int i=0;
while (i < n) {
if (c[i] < i) {
if ((i & 1) == 0)
swap(array, 0, i);
else
swap(array, c[i], i);
System.out.println(Arrays.toString(array)); //Consume permutation.
++c[i];
i=0;
}
else
c[i++] = 0;
}
}
public static void main(final String[] args) {
printPermutations_HeapsAlgorithm(4, new Character[]{'A', 'B', 'C', 'D'});
}
}
Possible duplicate of this.

How to create combinations of values in Java?

I have the following map: Map<Integer,String[]> map = new HashMap<Integer,String[]>();
The keys are integers and the values are arrays (could also be replaced by lists).
Now, I would like to get all possible combinations of the values among the keys. For example, let's say the map contains the following entries:
key 1: "test1", "stackoverflow"
key 2: "test2", "wow"
key 3: "new"
The combinations consists of
("test1","test2","new")
("test1","wow","new")
("stackoverflow", "test2", "new")
("stackoverflow", "wow", "new")
For this I imagine a method boolean hasNext() which returns true if there is a next pair and a second method which just returns the next set of values (if any).
How can this be done? The map could also be replaced by an other data structure.
The algorithm is essentially almost the same as the increment algorithm for decimal numbers ("x -> x+1").
Here the iterator class:
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeSet;
public class CombinationsIterator implements Iterator<String[]> {
// Immutable fields
private final int combinationLength;
private final String[][] values;
private final int[] maxIndexes;
// Mutable fields
private final int[] currentIndexes;
private boolean hasNext;
public CombinationsIterator(final Map<Integer,String[]> map) {
combinationLength = map.size();
values = new String[combinationLength][];
maxIndexes = new int[combinationLength];
currentIndexes = new int[combinationLength];
if (combinationLength == 0) {
hasNext = false;
return;
}
hasNext = true;
// Reorganize the map to array.
// Map is not actually needed and would unnecessarily complicate the algorithm.
int valuesIndex = 0;
for (final int key : new TreeSet<>(map.keySet())) {
values[valuesIndex++] = map.get(key);
}
// Fill in the arrays of max indexes and current indexes.
for (int i = 0; i < combinationLength; ++i) {
if (values[i].length == 0) {
// Set hasNext to false if at least one of the value-arrays is empty.
// Stop the loop as the behavior of the iterator is already defined in this case:
// the iterator will just return no combinations.
hasNext = false;
return;
}
maxIndexes[i] = values[i].length - 1;
currentIndexes[i] = 0;
}
}
#Override
public boolean hasNext() {
return hasNext;
}
#Override
public String[] next() {
if (!hasNext) {
throw new NoSuchElementException("No more combinations are available");
}
final String[] combination = getCombinationByCurrentIndexes();
nextIndexesCombination();
return combination;
}
private String[] getCombinationByCurrentIndexes() {
final String[] combination = new String[combinationLength];
for (int i = 0; i < combinationLength; ++i) {
combination[i] = values[i][currentIndexes[i]];
}
return combination;
}
private void nextIndexesCombination() {
// A slightly modified "increment number by one" algorithm.
// This loop seems more natural, but it would return combinations in a different order than in your example:
// for (int i = 0; i < combinationLength; ++i) {
// This loop returns combinations in the order which matches your example:
for (int i = combinationLength - 1; i >= 0; --i) {
if (currentIndexes[i] < maxIndexes[i]) {
// Increment the current index
++currentIndexes[i];
return;
} else {
// Current index at max:
// reset it to zero and "carry" to the next index
currentIndexes[i] = 0;
}
}
// If we are here, then all current indexes are at max, and there are no more combinations
hasNext = false;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Remove operation is not supported");
}
}
Here the sample usage:
final Map<Integer,String[]> map = new HashMap<Integer,String[]>();
map.put(1, new String[]{"test1", "stackoverflow"});
map.put(2, new String[]{"test2", "wow"});
map.put(3, new String[]{"new"});
final CombinationsIterator iterator = new CombinationsIterator(map);
while (iterator.hasNext()) {
System.out.println(
org.apache.commons.lang3.ArrayUtils.toString(iterator.next())
);
}
It prints exactly what's specified in your example.
P.S. The map is actually not needed; it could be replaced by a simple array of arrays (or list of lists). The constructor would then get a bit simpler:
public CombinationsIterator(final String[][] array) {
combinationLength = array.length;
values = array;
// ...
// Reorganize the map to array - THIS CAN BE REMOVED.
I took this as a challenge to see whether the new Java 8 APIs help with these kind of problems. So here's my solution for the problem:
public class CombinatorIterator implements Iterator<Collection<String>> {
private final String[][] arrays;
private final int[] indices;
private final int total;
private int counter;
public CombinatorIterator(Collection<String[]> input) {
arrays = input.toArray(new String[input.size()][]);
indices = new int[arrays.length];
total = Arrays.stream(arrays).mapToInt(arr -> arr.length)
.reduce((x, y) -> x * y).orElse(0);
counter = 0;
}
#Override
public boolean hasNext() {
return counter < total;
}
#Override
public Collection<String> next() {
List<String> nextValue = IntStream.range(0, arrays.length)
.mapToObj(i -> arrays[i][indices[i]]).collect(Collectors.toList());
//rolling carry over the indices
for (int j = 0;
j < arrays.length && ++indices[j] == arrays[j].length; j++) {
indices[j] = 0;
}
counter++;
return nextValue;
}
}
Note that I don't use a map as an input as the map keys actually don't play any role here. You can use map.values() though to pass in the input for the iterator. With the following test code:
List<String[]> input = Arrays.asList(
new String[] {"such", "nice", "question"},
new String[] {"much", "iterator"},
new String[] {"very", "wow"}
);
Iterator<Collection<String>> it = new CombinatorIterator(input);
it.forEachRemaining(System.out::println);
the output will be:
[such, much, very]
[nice, much, very]
[question, much, very]
[such, iterator, very]
[nice, iterator, very]
[question, iterator, very]
[such, much, wow]
[nice, much, wow]
[question, much, wow]
[such, iterator, wow]
[nice, iterator, wow]
[question, iterator, wow]

Sorting using comparable

Intro
My code to do a custom sort by using Comparable is not work the way I want it to. I'm basically taking an Array of directories and sorting them by:
First number of directories, the fewer comes first.
If it's a tie alphabetically.
The problem
An example of an input you be:
["/", "/usr/", "/usr/local/", "/usr/local/bin/", "/games/",
"/games/snake/", "/homework/", "/temp/downloads/" ]
Which should return this:
["/", "/games/", "/homework/", "/usr/", "/games/snake/",
"/temp/downloads/", "/usr/local/", "/usr/local/bin/" ]
But for some reason my code is return this:
["/", "/usr/", "/games/", "/homework/", "/usr/local/",
"/games/snake/", "/usr/local/bin/", "/temp/downloads/" ]
My code [edited with comments]
import java.util.*;
public class Dirsort { public String[] sort(String[] dirs) {
//Creates Array list containing Sort object
ArrayList<Sort> mySort = new ArrayList<Sort>();
//Loop that gets the 3 needed values for sorting
for (String d: dirs){
String [] l = d.split("/");//String array for alphabetical comparison
int di = d.length();//Length of array for sorting by number of directories
mySort.add(new Sort(di,l,d));//adds Sort object to arraylist (note d (the entire directory) is needed for the toString)
}
Collections.sort(mySort);//sorts according to compareTo
String [] ans = new String [mySort.size()];//Creates a new string array that will be returned
int count = 0;//to keep track of where we are in the loop for appending
for (Sort s: mySort){
ans[count] = s.toString();
count++;
}
return ans;
}
class Sort implements Comparable<Sort>{
private int d;//number of directories
private String [] arr;//array of strings of names of directories
private String dir;//full directory as string for toString
//Constructor
public Sort(int myD, String [] myArr, String myDir){
d = myD;
arr = myArr;
dir = myDir;
}
//toString
public String toString(){
return dir;
}
#Override
public int compareTo(Sort arg0) {
// TODO Auto-generated method stub
//If they are the same return 0
if (this.equals(arg0)){
return 0;
}
//if the directories are empty
if("/".equals(arg0.dir)){
return 1;
}
if ("/".equals(this.dir)){
return -1;
}
//If they are not the same length the shorter one comes first
if (this.d != arg0.d){
return this.d - arg0.d;
}
//If they are the same length, compare them alphabetically
else{
for (int i = 0; i < arg0.d; i++){
if (!this.arr[i].equals(arg0.arr[i])){
return this.arr[i].compareTo(arg0.arr[i]);
}
}
}
return 0;
}
}
}
The bug is here:
for (String d: dirs){
String [] l = d.split("/");
int di = d.length(); // <- here
mySort.add(new Sort(di,l,d));
}
Because there you are comparing the length of the entire directory String, not the number of 'folders' in the directory. That's why "/usr/" comes before "/homework/", for example, because:
"/usr/".length() == 5
"/homework/".length() == 10
I believe what you wanted was this, using the length of the split:
int di = l.length;
Then the output is:
/
/games/
/homework/
/usr/
/games/snake/
/temp/downloads/
/usr/local/
/usr/local/bin/
There's another small bug though (possibly), which is that calling split on a String that starts with the delimiter will result in an empty String at the beginning.
IE:
"/usr/".split("/") == { "", "usr" }
So you might want to do something about that. Though here it means that all of them start with the empty String so it doesn't end up with an effect on the way you're doing the comparison.
And as a side note, it's also true what #JBNizet is suggesting that giving your variables more meaningful names helps a lot here. fullDir.length() and splitDir.length would have made this much easier to spot (and it may have never happened in the first place).
Here's a fixed version of your code, which handles the case where both directories are "/", which removes the unnecessary, and incorrectly passed length of the parts array, and which uses more meaningful variable names:
public class Dirsort {
public static void main(String[] args) {
String[] input = new String[] {
"/",
"/usr/",
"/usr/local/",
"/usr/local/bin/",
"/games/",
"/games/snake/",
"/homework/",
"/temp/downloads/"
};
String[] result = new Dirsort().sort(input);
System.out.println("result = " + Arrays.toString(result));
}
public String[] sort(String[] dirs) {
ArrayList<Sort> sorts = new ArrayList<Sort>();
for (String dir : dirs) {
String[] parts = dir.split("/");
sorts.add(new Sort(parts, dir));
}
Collections.sort(sorts);
String[] result = new String[sorts.size()];
int count = 0;
for (Sort sort: sorts) {
result[count] = sort.toString();
count++;
}
return result;
}
class Sort implements Comparable<Sort> {
private String[] parts;
private String dir;
public Sort(String[] parts, String dir) {
this.parts = parts;
this.dir = dir;
}
public String toString(){
return dir;
}
#Override
public int compareTo(Sort other) {
if (this.equals(other)){
return 0;
}
if("/".equals(other.dir) && "/".equals(dir)) {
return 0;
}
if("/".equals(other.dir)){
return 1;
}
if ("/".equals(this.dir)){
return -1;
}
if (this.parts.length != other.parts.length){
return this.parts.length - other.parts.length;
}
else {
for (int i = 0; i < other.parts.length; i++){
if (!this.parts[i].equals(other.parts[i])){
return this.parts[i].compareTo(other.parts[i]);
}
}
}
return 0;
}
}
}
I spotted the problem by simply using my debugger and make it display the value of all the variables.
public class Disort
{
public static String[] sort(String[] dirs)
{
ArrayList<Path> mySort = new ArrayList<Path>();
Path pathDir;
for(String dir : dirs){
pathDir = Paths.get(dir);
// check if directory exists
if(Files.isDirectory(pathDir)){
mySort.add(pathDir);
}
}
// sort the ArrayList according a personalized comparator
Collections.sort(mySort, new Comparator<Path>(){
#Override
public int compare(Path o1, Path o2)
{
if(o1.getNameCount() < o2.getNameCount()){
return -1;
}
else if(o1.getNameCount() > o2.getNameCount()){
return 1;
}
else{
return o1.compareTo(o2);
}
}
});
// to return a String[] but it will better to return a ArrayList<Path>
String[] result = new String[mySort.size()];
for(int i = 0; i < result.length; i++){
result[i] = mySort.get(i).toString();
}
return result;
}
}

Categories