calculating the final length - java

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.

Related

Object information does not coincide with Array of Object's index

I'm trying to get the function infoEst() to iterate over an array of objects
and print out the object's name and location. It iterates fine but it seems like every
index in the array is the exact same as the last entry.
Am I creating the array of objects incorrectly?
import java.util.Scanner;
public class Estudiante {
static String nombre= "", promedio = "", pueblo = "", entrada = "";
static int edad;
static Estudiante[] objArray = new Estudiante[4];
static Scanner input = new Scanner(System.in);
Estudiante(String nom, int ed, String prom, String pueb) {
this.nombre = nom;
this.edad = ed;
this.promedio = prom;
this.pueblo = pueb;
}
static void infoEst(String n) {
for (int i = 0; i < objArray.length; i++) {
if (objArray[i].nombre == n) {
System.out.println(objArray[i].nombre + ", " + objArray[i].pueblo);
}
}
}
public static void main(String[] args) {
objArray[0] = new Estudiante("Joshua", 20, "A", "Aguadilla");
objArray[1] = new Estudiante("Liliana", 21, "A", "Isabella");
objArray[2] = new Estudiante("Cano", 27, "C", "Aguadilla");
objArray[3] = new Estudiante("Eribelto", 22, "F", "Moca");
// does not print anything when executed.
infoEst("Joshua");
infoEst("Liliana");
// the if statement block executes on index 0 so
// it prints Eribelto, Moca 4 times.
infoEst("Eribelto");
// All of these print "Eribelto" which is last in the array
System.out.println(objArray[0].nombre);
System.out.println(objArray[1].nombre);
System.out.println(objArray[2].nombre);
System.out.println(objArray[3].nombre);
}
}
It iterates fine but it seems like every index in the array is the exact same as the last entry.
static String nombre= "", promedio = "", pueblo = "", entrada = "";
Don't use static variables. This means each instance of the class shares the same information.

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.

Combine values of a list of data that are almost equal

so i asked before but it seems i wasnt clear enough of what im talking about, so im trying to make it clearer now:
what im trying to do is prepare data for an import. the data i get is human made an not very efficient, so im removing unnecessary entrys and try to combine the data as much as possible.
its for something like a configurator. the data i get looks something like this:
123 : 45 : AB = 12
This means: if Option 1 is 1 OR 2 OR 3 and Option 2 is 4 OR 5 and Option 3 is A OR B the result will be 1 AND 2
i created a class thats something like this:
Class Options{
String opt1;
String opt2;
String opt3;
String optResult;
//and some other stuff
boolean hasSameOptions(Options o){
return opt1.equals(o.opt1) && opt2.equals(o.opt2) && opt3.equals(o.opt3);
}
public void AddOptions(String options) {
for (String s : options.split("")) {
if (!optResult.contains(s)) {
optResult = optResult + s;
}
}
}
}
now, the data is repetitive and can be combined. Like:
12 : 45 : AB = 12
12 : 45 : AB = 3
12 : 45 : AB = 4
This would mean actually mean: 12 : 45 : AB = 1234
So, what i do is break the Strings apart to get only single values with the result, for example:
1 : 4 : A = 12
1 : 4 : B = 12
1 : 5 : A = 12
//and so on.
I make a list of all these Values and then try to Combine them again to get more efficient List.
The first step i do is get all Objects who have the same Options but different Results and combine the results. that happens like this:
public static List<Options> cleanList(List<Options> oldList) {
List<Options> newList = new ArrayList<>();
for (Options item : oldList) {
Options temp = findEqualOptions(newList, item);
if (temp != null)
temp.AddOptions(item.optResult);
else
newList.add(item);
}
return newList;
}
public static <T> T findByProperty(Collection<T> col, Predicate<T> filter) {
return col.stream().filter(Objects::nonNull).filter(filter).findFirst().orElse(null);
}
public static Options findEqualOptions(List<Options> list, Options opt) {
return findByProperty(list, d -> d.hasSameOptions(opt));
}
After that, i try to compress the list even more, by combining elements who have only ONE different value. For example:
1 : 2 : A = 12
1 : 3 : A = 12
-> 1 : 23 : A = 12
i do it like this:
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
Option o1 = list.get(i);
Option o2 = list.get(j);
int diff1 = 0;
int diff2 = 0;
int diff3 = 0;
int diff4 = 0;
if(!o1.opt1.equals(o2.opt1))
diff1 = 1;
if(!o1.opt2.equals(o2.opt2))
diff2 = 1;
//and so on
if((diff1+diff2+diff3+diff4)>1)
continue;
if(diff1 == 1)
o1.opt1 = o1.opt1 + o2.opt1;
//and so on...
list.remove(j--);
}
}
i do this until there are no more changes. It works well, but slowly. especially the method cleanList().
does anybody have any idea how to make it better? i tried to use a stream to get the whole list of equals options directly like this:
public static <T> List<T> findByMultipleValue(Collection<T> col, Predicate<T> filter) {
return col.stream().filter(filter).collect(Collectors.toList());
}
public static List<Options> getEqualOptionsList(List<Options> optList, Options opt){
return findByMultipleValue(optList, o -> o.hasSameOptions(opt));
}
but that made it A LOT slower.
PS. : its not the complete code, just an example of what im trying to do. I hope it is more understandable this time :)
probably not the most elegant or optimal solution but here is already a quick approach that give the result based on your description. It use the HashMap as proposed in the comment of #Joseph Larson
I went for a set of char to ensure values are not duplicate in it but feel free to adapt :)
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
class Scratch {
public static class Option{
String opt1;
String opt2;
String opt3;
String optResult;
public Option(String opt1, String opt2, String opt3, String optResult) {
this.opt1 = opt1;
this.opt2 = opt2;
this.opt3 = opt3;
this.optResult = optResult;
}
public static String merge(String a, String b){
StringBuilder value = new StringBuilder();
Set<Character> result = new HashSet<>();
for(char c : a.toCharArray()){
result.add(c);
}
for(char c : b.toCharArray()){
result.add(c);
}
for(char c : result){
value.append(c);
}
return value.toString();
}
public Option(Option a, Option b) {
this(merge(a.opt1, b.opt1), merge(a.opt2, b.opt2), merge(a.opt3, b.opt3), merge(a.optResult, b.optResult));
}
String getKey(){
return String.join(":", opt1, opt2, opt3);
}
int distance(Option option){
int diff1 = this.opt1.equals(option.opt1)?0:1;
int diff2 = this.opt2.equals(option.opt2)?0:1;
int diff3 = this.opt3.equals(option.opt3)?0:1;
int diff4 = this.optResult.equals(option.optResult)?0:1;
return diff1 + diff2 + diff3 + diff4;
}
public String toString(){
return getKey();
}
}
public static void main(String[] args) {
Option[] data = new Option[]{
new Option("12", "45", "AB", "12"),
new Option("12", "45", "AB", "3"),
new Option("12", "45", "AB", "4"),
new Option("12", "45", "AC", "1"),
new Option("12", "45", "AC", "12"),
new Option("3", "45", "AC", "13"),
new Option("12", "45", "AD", "12"),
};
mergeExact(data);
mergeClose(data, 1);
}
private static void mergeClose(Scratch.Option[] data, int distance){
Map<Option, Set<Character>> buffer = new HashMap<>();
for(Option option : data) {
boolean found = false;
Option toDelete = null;
for(Map.Entry<Option, Set<Character>> entry : buffer.entrySet()){
if(option.distance(entry.getKey()) <= distance){
Option merged = new Option(entry.getKey(), option);
for(char c : option.optResult.toCharArray()){
entry.getValue().add(c);
}
buffer.put(merged, entry.getValue());
toDelete = entry.getKey();
found = true;
break;
}
}
if(found) {
buffer.remove(toDelete);
}else{
Set<Character> set = new HashSet<>();
for(char c : option.optResult.toCharArray()){
set.add(c);
}
buffer.put(option, set);
}
}
System.out.println(String.format("merge with distance of %d:: %s", distance, buffer));
}
private static void mergeExact(Scratch.Option[] data) {
Map<String, Set<Character>> buffer = new HashMap<>();
for(Option option : data){
Set<Character> item = buffer.computeIfAbsent(option.getKey(), k -> new HashSet<>());
for(char c : option.optResult.toCharArray()){
item.add(c);
}
}
System.out.println("exact merge:: "+buffer);
}
}
output is
exact merge:: {3:45:AC=[1, 3], 12:45:AD=[1, 2], 12:45:AC=[1, 2], 12:45:AB=[1, 2, 3, 4]}
merge with distance of 1:: {12:45:AB=[1, 2, 3, 4], 3:45:AC=[1, 3], 12:45:ACD=[1, 2]}
EDIT: missed a part of the question, updating to add the merge when difference is close. This part is probably even worst that the first one in terms of optimisation but it's a working bases :)

How to retrieve element from ArrayList containing long array

How to retrieve element from ArrayList<long[]>?
I wrote like this:
ArrayList<long []> dp=new ArrayList<>();
//m is no of rows in Arraylist
for(int i=0;i<m;i++){
dp.add(new long[n]); //n is length of each long array
//so I created array of m row n column
}
Now how to get each element?
every element in that list is an array... so you need to carefully add those by:
using anonymous arrays new long[] { 1L, 2L, 3L }
or especifying the size using the new keyword new long[5]
public static void main(String[] args) throws Exception {
ArrayList<long[]> dp = new ArrayList<>();
// add 3 arrays
for (int i = 0; i < 3; i++) {
dp.add(new long[] { 1L, 2L, 3L });
}
// add a new array of size 5
dp.add(new long[5]); //all are by defaul 0
// get the info from array
for (long[] ls : dp) {
for (long l : ls) {
System.out.println("long:" + l);
}
System.out.println("next element in the list");
}
}
You get the arrays the same way you get anything from an ArrayList. For example, to get the tenth long[] stored in the ArrayList, you'd use the get method:
long[] tenthArray = dp.get(9);
You could also have an ArrayList of objetcs that contain an array of longs inside. But the problem so far with your code is that you are not putting any values in each long array.
public class NewClass {
private static class MyObject {
private long []v;
public MyObject(int n) {
v = new long[n];
}
#Override
public String toString() {
String x = "";
for (int i = 0; i < v.length; i++) {
x += v[i] + " ";
}
return x;
}
}
public static void main(String[] args) {
ArrayList<MyObject> dp = new ArrayList();
int m = 3;
int n = 5;
for (int i = 0; i < m; i++) {
dp.add(new MyObject(n));
}
for (MyObject ls : dp) {
System.out.println(ls);
}
}
}

random elements from a list DURING the addition

There are 20 names in my code.
my function has 2 options to add elements to a list I've:
1.
Inserting all the 20 names to the list:
public void addNames() {
list.add("name1");
list.add("name2");
...
list.add("name20");
}
2.
Adding only 5 random names(from the 20 names) to the list. For doing it, I thought about 2 ways. What's the best way to random 5 names from the 20? maybe you have a better way.
A.
Using a random set of indices (each value will be between 0 to 19 because there are 20 names) and before the 'add' I'll check if adding them or not by some counter:
public void addNames() {
// adding 5 random indices between 0 to 19 to the set
Set<Integer> set = new HashSet<Integer>();
Random r = new Random();
Set<Integer> indices = new HashSet<>(numRandomNames); //==5
for (int i = 0; i < numRandomNames; ++i) {
int index = r.nextInt(numNames - 0); //==19
indices.add(index);
}
int counter = 0;
if (indices.contains(counter)) {
list.add("name1");
}
counter++;
if (indices.contains(counter)) {
list.add("name2");
}
counter++;
if (indices.contains(counter)) {
list.add("name3");
}
...
}
B.
RandomList that extends List and overrides the 'add' function to do the same as 'A.' does BUT the override 'add' will decide whether adding the value inside the function so my function will look the same as 1. with the override 'add' function
Do you think about a better solution? if not, then which one is better? (A or B?). I just saw that people recommends not to extend the java collection but I think it's the best solution from these 2 solutions.
NOTE
====
my code can have 10000 names or more even so I don't want to add all the 10,000 names to this\other list and then random 5 of them to other list. I prefer to do it DURING the addition in order to avoid many places of the list while I don't really need them.
EDIT
an answer to ProgrammerTrond:
I'm not sure I'll do it but what I asked me to show is my suggestion of 2.B:
public class RandomList<Integer> implements List<Integer> {
private int addCallsCounter;
private Set<Integer> setIndices = null;
public RandomList(final int numElements, final int maxVal, final int minVal) {
addCallsCounter = 0;
setIndices = new HashSet<Integer>(numElements);
Random r = new Random();
while (setIndices.size() < numElements) {
int index = r.nextInt(maxVal - minVal + 1) + minVal;
if (setIndices.contains(index) == false) {
setIndices.add(index);
}
}
}
#Override
public boolean add(Integer object) {
if (setIndices.contains(addCallsCounter++)) {
this.add(object);
return true;
}
return false;
}
}
and from my code I'll do so:
RandomList randList = new RandomList(5);
randList.add("name1");
randList.add("name2");
randList.add("name3");
...
randList.add("name19");
randList.add("name20");
but my problem is that I need to implement MANY abstract methods of List pfff. RandomList cann't be abstract too because then it won't be able to be instantiated.
try this:
List<Integer> index = new ArrayList<>();
List<String> five_names = new ArrsyList<>();
List<String> allnames = new ArrayList<>();
store five random values
for(int i = 0;i < 5;i++){
int index_no = getrandomNumber();
index.add(index_no);
five_names.add(allnames.get(index_no));
}
getRandomNumber method:
public int getRandomNumber(){
Random rnd = new Random();
int x = rnd.nextInt(20);
if(index.contains(x)){
return getRandomNumber();
}else{
return x
}
}
Why not like this? You don't need the random index list in your list implementation. Didn't you just want a method that would add to a list 5 random names drawn from a set of available names?
import java.util.*;
public class ListAdding {
private static List<String> allNames = Arrays.asList("name1", "name2", "name3", "name4", "name5", "name6", "name7");
public static void main(String[] args) {
new Temp().test();
}
void test() {
List<String> list = new ArrayList<>();
list.add("Bernie");
addFiveRandom(list);
for (int i = 0; i < list.size(); i++) {
System.out.println(i + ": " + list.get(i));
}
// Example: 0: Bernie
// 1: name2
// 2: name3
// 3: name6
// and so on
}
void addFiveRandom(List<String> toBeAddedTo) {
List<Integer> indices = new ArrayList<>();
while (indices.size() < 5) {
int newIndex = new Random().nextInt(5);
if (!indices.contains(newIndex))
indices.add(newIndex);
}
for (Integer index : indices) {
toBeAddedTo.add(allNames.get(index));
}
}
}

Categories