Java Code optimization : if else to resolve PMD complexity 24 to 0 - java

I have string of array with size already defined and i have to iterate though this array and fill it with fields value of someObject I have . If i do this with if elseif elseif or switch case i get high complexity .. please kindly suggest proper way to do this

I would suggest you to use a map to keep the mapping like this:
private static final Map<Integer, String> MAP_VALUES = new HashMap<Integer, String>();
private static Map<Integer, String> getMapValues(Employe employe){
if(MAP_VALUES.isEmpty()){
MAP_VALUES.put(0, employe.getEmployeeI());
MAP_VALUES.put(1, employe.getEmployeeLastName());
MAP_VALUES.put(2, employe.getEmployeeDivision());
....
}
return MAP_VALUES;
}
public String getValueForEmploye(Employe employe){
String[] value = ...;
for(int i = 0; i < value.length; i++){
value[i] = getMapValues(employe).get(i);
}
}

Related

Is there a Map object with takes index and key and object? Java

I'm trying to emulate a rotor of an enigma machine in Java.
I need an object which takes an index, a key and an object, because I unsuccessfully tried HashMaps like this:
private HashMap<Integer,Integer> rotorWiring = new HashMap<Integer, Integer();
private HashMap<Integer,Integer> reverseRotorWiring = new HashMap<Integer, Integer>();
//The "wiring" of the rotor is set from a String,
public void setRotorWiring(String Wiring) {
if (Wiring.length()==26) {
for (int i=0; i<Wiring.length();i++ ) {
char tempChar = Wiring.charAt(i);
int valueOfChar = (int)tempChar-64;
if (valueOfChar<=26){
this.rotorWiring.put(i+1,valueOfChar);
this.reverseRotorWiring.put(valueOfChar,i+1);
}
}
}
}
So far so good, this allows me to translate e.x. an A to an E, however, once I tried to simulate a turn of the rotor like this:
//It should be mentioned that I designing the program to only accept characters a to z inclusive.
public void turn() {
for (int i=1;i<=rotorWiring.size();i++) {
if (i!=26) {
rotorWiring.replace(i, rotorWiring.get(i+1));
}
else {
rotorWiring.replace(i, rotorWiring.get(1));
}
}
for (int i=1;i<=rotorWiring.size();i++) {
if (i!=26) {
reverseRotorWiring.replace(i, rotorWiring.get(i+1));
}
}
}
However, I noticed that this rather simulates an offset of the internal wiring of the rotor rather than a turn... I'm asking for a "Map"-like solutions with an index, key and object, because that would allow me to offset the index of all the keys and objects by 1, thus simulating a turn.
I am, however, open to suggestions for different solutions to this problem.
It should be mentioned that I'm a bit of a novice, and therefore appreciate rather in-depth explanations.
Many thanks.
Welcome to StackOverflow. There doesn't exist an implementation of what you have described in JDK. However, there are more ways to achieve the storing of Integer-String-Object. Note that both the index and the key are unique by definition. Also, note that the index-key are tightly coupled. You might want to put a Map to another Map:
Map<Integer, Map<String, MyObject>> map;
Or use a collection characteristic for indices:
List<Map<String, MyObject>>
Be careful with removing items which change the index of all the subsequent elements - replace it with null instead to keep the indices. Alternatively, you can create a decorator for your defined object with index/key:
Map<Integer, MyDecoratedObject> map;
Where the MyDecoratedObject would look like:
public class MyDecoratedObject {
private final String key; // or int index
private final MyObject delegate;
// Full-args constructor, getters
}
Finally, it's up to you to pick a way that satisfied your requirements the most.
A map of maps was the solution! It was solved like this:
private HashMap<Integer,HashMap<Integer,Integer>> rotorWiring = new HashMap<Integer, HashMap<Integer,Integer>>();
private HashMap<Integer,HashMap<Integer,Integer>> reverseRotorWiring = new HashMap<Integer, HashMap<Integer,Integer>>();
public void setRotorWiring(String Wiring) {
if (Wiring.length()==26) {
for (int i=0; i<Wiring.length();i++ ) {
HashMap<Integer, Integer> wire = new HashMap<Integer, Integer>();
HashMap<Integer, Integer> reverseWire = new HashMap<Integer, Integer>();
char tempChar = Wiring.charAt(i);
int valueOfChar = (int)tempChar-64;
if (valueOfChar<=26){
wire.put(i+1,valueOfChar);
reverseWire.put(valueOfChar,i+1);
rotorWiring.put(i, wire);
reverseRotorWiring.put(i, reverseWire);
}
}
}
}

Fast way to compare String[] to List

I would like to compare String arrays to a list with market objects.
I implemented the code like that:
private List<Data> addMarketData(List<Data> list) {
String[] SEE = new String[]{"Albania", "Bosnia and Herzegovina", "Bulgaria", "Croatia", "Macedonia FYR", "Moldavia", "Montenegro", "Romania", "Serbia", "Slovenia" };
List<String> seeList = Arrays.asList(SEE);
String[] CEE = new String[]{"Czech Republic", "Hungary", "Poland", "Slovakia"};
List<String> ceeList = Arrays.asList(CEE);
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < seeList.size(); j++) {
if(list.get(i).getPropertyCountry().equals(seeList.get(j).toString())) {
list.get(i).setMarket("SEE");
}
}
for (int k = 0; k < ceeList.size(); k++) {
if(list.get(i).getPropertyCountry().equals(ceeList.get(k).toString())) {
list.get(i).setMarket("CEE");
}
}
}
return list;
}
However, I believe that this code produces more overhead than it really should. Especially the for loops. Could I just use one loop?
Therefore, how to make this piece of code much faster?
I appreciate your answer!
Move all the data into a Set<String>:
String[] SEE = ...
Set<String> setSEE = new HashSet<>(Arrays.asList(SEE));
String[] CEE = ...
Set<String> setCEE = new HashSet<>(Arrays.asList(CEE));
for (Data data : list) {
if (setSEE.contains(data.getPropertyCountry()) {
data.setMarket("SEE");
} else if (setCEE.contains(data.getPropertyCountry()) {
data.setMarket("CEE");
}
}
This won't generate the overhead you may think. Also, it is faster than your current O(N^2) approach.
Another idea is to move the data of these arrays into a Map<String, String> as proposed by #Narmer, but in this case you should define a value when the country is not found as key in the map.
Since Java 7, you can use diamond operator. For Java 5 and 6, you have to specify the whole generics usage:
Set<String> setSEE = new HashSet<String>(Arrays.asList(SEE));
//...
Set<String> setCEE = new HashSet<String>(Arrays.asList(CEE));
Define seeList and ceeList as HashSets and then use its contains() method. HashSet's contains() has constant time complexity.
Set<String> seeSet = new HashSet<>();
Collections.addAll(seeSet, SEE);
Set<String> ceeSet = new HashSet<>();
Collections.addAll(ceeSet, CEE);
And then:
for (int i = 0; i < list.size(); i++) {
if (seeSet.contains(list.get(i).getPropertyCountry()) {
list.get(i).setMarket("SEE");
}
if (ceeSet.contains(list.get(i).getPropertyCountry()) {
list.get(i).setMarket("CEE");
}
}
You could use a Map instead of list.
private static final Map<String, String> markets = new HashMap<String,String>(){{
put("Albania", "SEE");
put("Bosnia and Herzegovina", "SEE");
...
put("Hungary", "CEE");
...
}}
Then consult it
for(Data data: list){
data.setMarket(markets.get(data.getPropertyCountry()));
}
EDIT
As per the comments, the above is the optimal situation. You should check that data.getPropertyCountry() is not null (if permitted) and that the value returned by the list ins't null either:
for(Data data: list){
if(data.getPropertyCountry()!=null){
String market = markets.get(data.getPropertyCountry());
data.setMarket(market==null?"default market":market);
}
else data.setMarket("default value"); //if needed
}
Or using the beatiful Java 8 stream interface:
for(Data data: list.stream().filter(p -> p.getPropertyCountry() != null).collect(Collectors.toList())){
String market = markets.get(data.getPropertyCountry());
data.setMarket(market==null?"default market":market);
}
Well you can simply use two HashSet<String> collections to store the name of the countries in. A HashSet<String> performs lookups in approximately O(1) time per item, this O(n) for the entire array. Or you could use one HashMap<String,String> to perform lookups resulting in "SEE" or "CEE".
Example
Map<String,String> lut = new HashMap<String,String>();
for(String s : new String[]{"Albania", "Bosnia and Herzegovina", "Bulgaria", "Croatia", "Macedonia FYR", "Moldavia", "Montenegro", "Romania", "Serbia", "Slovenia" }) {
lut.put(s,"SEE");
}
for(String s : new String[]{"Czech Republic", "Hungary", "Poland", "Slovakia"}) {
lut.put(s,"CEE");
}
for (Data data : list) {
data.setMarket(lut.get(data.getPropertyCountry()));
}
The generation of the HashMap<String,String> (and putting data into it) should only be executed once (at startup). This will increase performance with a factor equal to the number of elements you put into the HashMap<String,String> (in this case 14).

Using a string to write to an array

Attempting to tidy up code, originally I was using this method of writing to arrays, which is ridiculously long when I have to repeat it 20 times
if (ant.getAntNumber() == 3)
{
numbers3.add(ant.getCol());
numbers3y.add(ant.getRow());
}
if (ant.getAntNumber() == 4)
{
numbers4.add(ant.getCol());
numbers4y.add(ant.getRow());
}
I attempted to use a for loop to do it but I cant figure out how to add to the array using the string value, because it thinks its a string rather than trying to use the array
for (int j = 0; j<maxAnts; j++)
{
String str = "numbers" + j;
String str2 = "numbers" + j + "y";
//this part doesnt work
str.add(ant.getCol());
}
Any suggestions would be helpful
In Java, you cannot use the value of a String object to reference an actual variable name. Java will think you're attempting to to call add on the String object, which doesn't exist and gives you the compiler error you're seeing.
To avoid the repetition, you need to add your Lists to two master lists that you can index.
In your question, you mention arrays, but you call add, so I'm assuming that you're really referring to Lists of some sort.
List<List<Integer>> numbers = new ArrayList<List<Integer>>(20);
List<List<Integer>> numbersy = new ArrayList<List<Integer>>(20);
// Add 20 ArrayList<Integer>s to each of the above lists in a loop here.
Then you can bounds-check ant.getAntNumber() and use it as an index into your master lists.
int antNumber = ant.getAntNumber();
// Make sure it's within range here.
numbers.get(antNumber).add(ant.getCol());
numbersy.get(antNumber).add(ant.getRow());
How about this?
Ant[] aAnt = new Ant[20];
//Fill the ant-array
int[] aColumns = new int[aAnt.length];
int[] aRows = new int[aAnt.length];
for(int i = 0; i < aAnt.length; i++) {
aColumns[i] = aAnt[i].getCol();
aRows[i] = aAnt[i].getRow();
}
or with lists:
List<Integer> columnList = new List<Integer>(aAnt.length);
List<Integer> rowList = new List<Integer>(aAnt.length);
for(Ant ant : aAnt) {
columnList.add(ant.getCol());
rowList.add(ant.getRow());
}
or with a col/row object:
class Coordinate {
public final int yCol;
public final int xRow;
public Coordinate(int y_col, int x_row) {
yCol = y_col;
xRow = x_row;
}
}
//use it with
List<Coordinate> coordinateList = new List<Coordinate>(aAnt.length);
for(Ant ant : aAnt) {
coordinateList.add(ant.getCol(), ant.getRow());
}
A straight-forward port of your code would be to use two Map<Integer, Integer> which store X and Y coordinates. From your code it seems like ant numbers are unique, i.e., we only have to store a single X and Y value per ant number. If you need to store multiple values per ant number, use a List<Integer> as value type of the Map instead.
Map<Integer, Integer> numbersX = new HashMap<Integer, Integer>();
Map<Integer, Integer> numbersY = new HashMap<Integer, Integer>();
for(Ant ant : ants) {
int number = ant.getAntNumber();
numbersX.put(number, ant.getCol());
numbersY.put(number, ant.getRow());
}

String Array Into HashMap Collection Object

I have the following
String[] temp;
which returns
red
blue
green
I would like to add the string array into a collection obejct like HashMap so that I could retrieve values in any class like
HashMap hash = New HashMap();
hash.get("red");
hash.get("blue");
hash.get("green");
How can I do this?
Thanks
Update 1
String str = "red,blue,green";
String[] temp;
String delimiter = ",";
temp = str.split(delimiter);
for (int i = 0; i < temp.length; i++) {
System.out.println(temp[i]);
}
With the above code, I would like to retrieve values based on values in array. E.g. I would like to get the values in from another class by calling hash.get("One"), which would return red, hash.get("Two") which would return blue and so forth.
Map<String, String> hash = new HashMap<String, String>();
for(i = 0 ; i < temp.length(); i++)
{
hash.put(temp[i], temp[i]);
}
Then you can retrieve from map
hash.get (temp[i]);
HashMap<String, String>() map = new HashMap<String, String>();
map.put(temp[i], temp[i]);//here i have considered key as the value itself.. u can use something else //also.
My doubt how I do map temp[i] with red, blue or green?
Using a hash map won't solve this problem directly. Currently you need to write
temp[ someNumberHere ];
so
temp[ 1 ];
yields a String "blue"
If you have a hashMap then instead you might write
myColourMap.get( someNumberHere );
so
myColourMap.get( 1 );
Would yield "blue". In either case you are converting a value to a corresponding string, but you do need to know that "someNumber". If you want "blue" you need to know to ask for number 1.
It may be that what you need is to use nicely named constant values:
public Class Colours {
public static final int RED = 0;
public static final int BLUE = 1;
public static final int GREEN = 1;
// plus either the array of strings or the hashMap
public statuc String getColour(int colourNumber ) {
return myArray[colourNumber]; // or myMap.get(colourNumber)
}
}
Your clients can now write code such as
Colours.getColour( Colour.RED );
[It is better to use enums than just raw ints, but let's not divert from arrays and hashMaps right now].
Now when might you prefer a hashMap instead of an array? Consider that you might have more colours, for example 12695295 might be "light pink" and 16443110 might be "lavender".
Now you really don't want an array with 16,443,110 entries when you are only using perhaps 500 of them. Now a HashMap is a really useful thing
myMap.put( Colour.LAVENDER, 16443110 );
and so on.

java linkedhashmap iteration

I have two hashmap
LinkedHashMap<String, int[]> val1 = new LinkedHashMap<String, int[]>();
LinkedHashMap<String, int> val2 = new LinkedHashMap<String, int>();
each hashmap has different key and values. I am trying to iterate over both hashmap
at the same time and multiply each value of val1->int[] to val2->int
What is the easiest and fasted way to do it? I have thousands values in both hashmap.
Thanks
You are probably doing it wrong...
First, a HashMap can't store ints, it needs proper objects - like Integer
– An array is an object, although it's hidden behind some syntactic sugar.
Here's how to loop over both maps, if they happens to have the same size,
which is what I think you mean.
Iterator<int[]> expenses = val1.values().iterator();
Iterator<Integer> people = val2.values().iterator();
assert val1.size() == val2.size() : " size mismatch";
while (expenses.hasNext()) {
int[] expensesPerMonth = expenses.next();
int persons = people.next();
// do strange calculation
int strangeSum = 0;
for (int idx = 0; idx < expensesPerMonth.length; idx++) {
strangeSum += persons * expensesPerMonth[idx];
}
System.out.println("strange sum :" + strangeSum);
}
But You should probably go back and rethink how you store your data –
why are you using maps, and whats the key?
Wouldn't it be better to create an object that represents the combination of monthly expenses and number of people, for instance?
AFAIK, a LinkedHashMap has iteration ordering. So, something like this may work:
Iterator myIt1 = val1.entrySet().iterator();
Iterator myIt2 = val2.entrySet().iterator();
while(val1.hasNext() && val2.hasNext()) {
int myarray[] = val1.next();
for(int i = 0; i<myarray.length; i++) {
myarray[i] = myarray[i] * val2.next();
}
}

Categories