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.
Related
Here is sample code I found. It works because the entire data structure is initialized in one statement.
Object[][] data =
{
{"Buy", "IBM", new Integer(1000), new Double(80.5), Boolean.TRUE},
{"Sell", "Dell", new Integer(2000), new Double(6.25), Boolean.FALSE},
{"Short Sell", "Apple", new Integer(3000), new Double(7.35), Boolean.TRUE},
{"Buy", "MicroSoft", new Integer(4000), new Double(27.50), Boolean.FALSE},
{"Short Sell", "Cisco", new Integer(5000), new Double(20), Boolean.TRUE}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames)
{
public Class getColumnClass(int column)
{
return getValueAt(0, column).getClass();
}
};
I need to manage a data model with thousands of rows. I have tried five different approaches for loading values (One String, four Integers, and one Double make up a row). The only way I have been able to get the table to display at all is to treat everything as strings. This would require a comparator for the Double column as natural String ordering doesn't cut it.
Below I have shown my latest attempt. The crux of my problem is the ArrayStoreException that happens at the line indicated -->
class RankingsDataModel extends DefaultTableModel {
static final String s = "";
static final Integer i = 0;
static final Double d = 0.0;
static String[] columnNames = { "Key", "Net IMPs", "Count", "Max IMPs", "Min IMPs", "Avg IMPs" };
static int[] widths = new int[] { 16, 16, 16, 16, 16, 16 };
Object[][] rows = new Object[S.getCurrentArchive().partnerCensus.size() > 9 ? S.getCurrentArchive().partnerCensus.size() : 9][getColumnCount()];
public int getColumnCount() { return columnNames.length; }
public int getRowCount() { return S.getCurrentArchive().partnerCensus.size() > 9 ? S.getCurrentArchive().partnerCensus.size() : 9; }
public String getColumnName(int col) { return columnNames[col]; }
public Object getValueAt(int row, int col) { return rows[row][col]; }
public Class getColumnClass(int c) { return c == 0 ? s.getClass() : c == 5 ? d.getClass() : i.getClass(); }
public boolean isCellEditable(int row, int col) { return false; }
}
class Row {
Integer net;
Integer count;
Integer max;
Integer min;
Double avg;
}
private void loadRankingsTable) {
int r = 0;
model.rows = new String[S.getCurrentArchive().partnerCensus.size()][6];
for (String p : S.getCurrentArchive().partnerCensus) {
PartnerDealFilter pf = new PartnerDealFilter(p);
addModelRow(pf, p, r++);
}
}
private void addModelRow(DealFilter f, String key, int r) {
Archive a = S.getCurrentArchive().getFilteredArchive(f);
Integer max = -24; Integer min = 24;
Integer count = 0;
for (DealNode dn : a.getDeals()) {
Integer imps = dn.getIMPsVsPar();
if (imps != null) {
count++;
if (imps < min) min = imps;
if (imps > max) max = imps;
}
}
String[] strings = { key };
Integer[] integers = { count, a.getNetIMPs(), max, min };
Double[] doubles = { a.getAvgIMPs() != null ? a.getAvgIMPs() : -24.01 };
--> model.rows[r][0] = strings[0];
model.rows[r][1] = Integers[0]);
model.rows[r][2] = integers[1];
model.rows[r][3] = integers[2];
model.rows[r][4] = integers[3];
model.rows[r][5] = doubles[0];
}
Previous attempts involved simpler efforts. I cannot store my table data in the model.
I know I am missing something simple. Please help.
I expected the data model to be loaded. I received a java.lang.ArrayStoreException in the AWT EventQueue thread.
The initial code created an Object[][] array and you created a String[][] array, so, storing any non-String value will inevitably crash. You will need to create an Object[][] to support Integer and Double values as well.
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;
}
}
}
I have following data in string(comma format) (Name,Mark)
A,20,B,10,C,30
I want to convert into Descending order like :
C,30,A,29,B,10
Please help me how can i implement in android ?
Here is code what i have prepared....
public class custom_sort {
public String name;
public int mark;
public custom_sort(String a, int b) {
// TODO Auto-generated constructor stub
name = a;
mark = b;
}
void setname(String s)
{
name=s;
}
void setmark(int s)
{
mark = s;
}
String getname()
{
return(name);
}
int getmark()
{
return(mark);
}
}
Thanks in Advance,
There are many ways of doing this. I see that you have already made a class: custom_sort. We can use this to sort it, if we just make it comparable. We do this by implementing the Comparable interface.
public class custom_sort implements Comparable{
Then all you need to do is implement the one required method:
#Override
public int compareTo(custom_sort cs) {
/*
This method should return 0 if the two objects are equal,
1 if this is biggest
and -1 if cs is biggest */
}
Then you can put all the custom_sorts in an List and just do Arrays.sort(yourArray).
You could also check out this post Android sort array
Use ArrayList rather than array of string.
This might not be the best solution but it works.
Initialize the ArrayList
ArrayList<String> names = new ArrayList<>();
ArrayList<Integer> scores = new ArrayList<>();
Fill data inside the ArrayList
names.add("A");
scores.add(20);
....
Now sort them
private void sortScoreAndName() {
for (int i = 0; i < scores.size(); i++) {
for (int j = 0; j < i; j++) {
if (scores.get(i) > scores.get(j))
swap(i, j);
}
}
}
private void swap(int i, int j) {
int tempSco = scores.get(i);
String tempName = names.get(i);
scores.remove(i);
names.remove(i);
scores.add(i, scores.get(j));
names.add(i, names.get(j));
scores.remove(j);
names.remove(j);
scores.add(j, tempSco);
names.add(j, tempName);
}
Now your ArrayList is in descending order. You can get the corresponding data using.
names.get(poition);
scores.get(position);
try this:
import android.support.v4.util.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
String[] values = {"A", "20", "B", "10", "C", "30"};
List<Pair> pairs = new ArrayList<>();
for (int i = 0; i < values.length; i += 2) {
pairs.add(new Pair<>(values[i], Integer.parseInt(values[i + 1])));
}
Collections.sort(pairs, new Comparator<Pair>() {
#Override
public int compare(Pair lhs, Pair rhs) {
return ((Integer) rhs.second).compareTo((Integer) lhs.second);
}
});
The List pairs is now sorted like you wish. Check out the Pair class i used http://developer.android.com/reference/android/util/Pair.html
And if you want to convert it back following code will help you:
String[] newValues = new String[values.length];
int i = 0;
for (Pair pair : pairs) {
newValues[i] = (String) pair.first;
newValues[i + 1] = Integer.toString((Integer) pair.second);
i += 2;
}
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
}
The following code separates the duplicate names into 1 column and sum of numbers associated with the names into the second column.
Like :
Nokia 21
Blackberry 3
Nimbus 30
from the array given in the program.
I want to know the final length of the array that contain these entries. In this case 3. How do i calculate that ?
package keylogger;
import java.util.ArrayList;
import java.util.List;
public class ArrayTester {
private static int finalLength = 0;
private static String Name[][];
private static String data[][] = {
{"Nokia" , "7"},
{"Blackberry" ,"1"},
{"Nimbus","10"},
{"Nokia" , "7"},
{"Blackberry" , "1"},
{"Nimbus","10"},
{"Nokia" , "7"},
{"Blackberry" , "1"},
{"Nimbus","10"}
};
public void calculator() {
Name = new String[data.length][2];
List<String> marked = new ArrayList<String>();
try {
for(int i=0;i<data.length;i++) {
Name[i][0] = data[i][0];
Name[i][1] = data[i][1];
String name = data[i][0];
if(marked.contains(name)) {
continue;
}
marked.add(name);
int k = i + 1;
int v = k;
for (int j = 0; j < data.length - v; j++) {
String s = data[k][0];
if(Name[i][0].equalsIgnoreCase(s)) {
Name[i][0] = s;
Integer z = Integer.parseInt(Name[i][1]) + Integer.parseInt(data[k][1]);
Name[i][1] = z.toString();
}
k++;
}
}
}catch(Exception exc) {
exc.printStackTrace();
}
}
public static void main(String args[]) {
ArrayTester o = new ArrayTester();
o.calculator();
for(String s[] : Name) {
for(String x : s) {
System.out.println(x);
}
}
}
}
As usual, the "problem" is poor coding. Your entire program, properly written, can be reduced to just 3 lines of code (5 if you include defining the array and printing the output):
public static void main(String[] args) {
String data[][] = {{"Nokia", "7"}, {"Blackberry", "1"}, {"Nimbus", "10"},
{"Nokia", "7"}, {"Blackberry", "1"}, {"Nimbus", "10"}, {"Nokia", "7"},
{"Blackberry", "1"}, {"Nimbus", "10"}, {"Zebra", "78"}};
HashMap<String, Integer> totals = new HashMap<String, Integer>();
for (String[] datum : data)
totals.put(datum[0], new Integer(datum[1]) + (totals.containsKey(datum[0]) ? totals.get(datum[0]) : 0));
System.out.println("There are " + totals.size() + " brands: " + totals);
}
Output:
There are 4 brands: {Nimbus=30, Zebra=78, Nokia=21, Blackberry=3}
You can't know it a priori, the size will be known just when you'll have finished splitting the strings and doing your math.
In your example in the end marked.size() will have the size you are looking for but I'd suggest you to directly use a HashMap so that you won't care about searching for existing elements in linear time and then convert it to an array.
Something like:
String[][] names = new String[map.size()];
Set<String> keys = map.keys();
int c = 0;
for (String k : keys)
{
names[c] = new String[2];
names[c][0] = k;
names[c++][1] = map.get(k).toString();
}
As far as I understand it, you want to know the number of distinct names in your array without calling calculator(), right? I don't really know if that makes sense as you still have to go through every entry and compare it with a set. But you could do it with a Set:
private int getNumberOfEntries(String[][] data) {
Set<String> names = new HashSet<String>();
for (int i=0; i<data.length; i++) {
names.add(data[i][1]);
}
return names.size();
}
Now you can just call int n = getNumberOfEntries(data);...
EDIT: Of course it makes more sense to do the sums in the same step, see Bohemians solution for that.