Switch case implementation in Java for an integer pair combination - java

I have following python code -
def get_subject_from_stream_id_and_subject_id(stream_id, subject_id):
#(stream_id, subject_id): ("subject_name")
return {
(1, 1): "Accounts",
(1, 2): "English",
(1, 3): "Organization of Commerce",
(2, 1): "Physics",
(2, 2): "English",
(2, 3): "Biology"
}.get((stream_id, subject_id), "None")
In this code, I want to get subject name from the integer pair combination i.e. stream_id, subject_id e.g. (1, 2) is for English. It was implemented using python tuple.
I want to implement the same piece of code in Java.
Could someone write this in a better way in Java?
public String getSubjectFromStreamIdAndSubjectId(int streamId, int subjectId) {
switch (streamId) {
case 1:
switch (subjectId) {
case 1:
return "Accounts";
case 2:
return "English";
case 3:
return "Organization of Commerce";
default:
return null;
}
case 2:
switch (subjectId) {
case 1:
return "Physics";
case 2:
return "English";
case 3:
return "Biology";
default:
return null;
}
default:
return null;
}
}
Thank you.

I don't like the solution presented in the duplication suggestion Switching on a pair of `int`s.
for two reasons:
The solution relies on external logic (Integer.valueOf() and switch of String) while it is not probable, the implementations may vary in future JDK releases
the switch-case was designed as shorthand for series of if statements. is not the best solution for mapping input to output values. A better solution is to utilize the Map data structure
The proper solution in my eyes would involve some kind Java Tuple. while there is no Tuple in the JDK, one can be easily constructed as user defined class. In fact, there is already an SO answer about that: A Java collection of value pairs? (tuples?)
so if we use the class from the above-mentioned answer as Map key, the solution is fairly easy and much more extensible (you could, for instance, load the map from an external resource like text file or DB table):
// initialized using instance initializer
Map<Pair<Integer, Integer>, String> streamIdAndSubjectIdMap = new HashMap<>()
{
{
put(new Pair(1, 1), "Accounts");
put(new Pair(1, 2), "English");
put(new Pair(1, 3), "Organization of Commerce");
}
};
public String getSubjectFromStreamIdAndSubjectId(int streamId, int subjectId) {
return streamIdAndSubjectIdMap.get(new Pair<>(streamId, subjectId));
}

Personally, i would really recommend to not use the switch statement here, since any hacks (like String concatenation) will just complicate things. However, you could refactor this method to use a regular if expression with a return statement.
public static String getSubject(int streamId, int subjectId) {
Pair<Integer> pair = Pair.of(streamId, subjectId);
if (pair.equals(Pair.of(1, 1))) {
return "Subject";
}
if (pair.equals(Pair.of(1, 2))) {
return "English";
}
if (pair.equals(Pair.of(1, 3))) {
return "Organization of Commerce";
}
if (pair.equals(Pair.of(2, 1))) {
return "Physics";
}
if (pair.equals(Pair.of(2, 2))) {
return "English";
}
if (pair.equals(Pair.of(2, 3))) {
return "Biology";
}
return null;
}
At least to my eye, this looks very clean and there is no need to use an if-else expression. One thing to note here is that the Pair class needs to be implemented correctly regarding equals and hashCode for this to work. An example implementation might be the following (tough it can still be extended):
public class Pair<T> {
private T first;
private T second;
public static <T> Pair<T> of(T first, T second) {
return new Pair<>(first, second);
}
private Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?> pair = (Pair<?>) o;
return Objects.equals(first, pair.first) &&
Objects.equals(second, pair.second);
}
#Override
public int hashCode() {
return Objects.hash(first, second);
}
}

It is not always recomended but in your case i would go with a nested ternary operator. If you have more combinations than given in your example this aproach could end in confusing, unreadable code. But if you have only those well defined cases:
public static String getSubjectFromStreamIdAndSubjectId(int stream_id, int subject_id) {
return stream_id == 1 ?
subject_id == 1 ? "Accounts" :
subject_id == 2 ? "English" :
subject_id == 3 ? "Organization of Commerce" : "None":
stream_id == 2 ?
subject_id == 1 ? "Physics" :
subject_id == 2 ? "English" :
subject_id == 3 ? "Biology" : "None":
"None";
}

Related

How To Improve Conditional Logic With Java 8

I'm in the process of learning Java 8 and I wanted to know if there was a clean way to re-write the below code more efficiently in Java 8:
public static Map<String, Character> parseOrg(String org) {
Map<String, Character> map = new HashMap<String, Character>();
if (org != null && !org.isEmpty()) {
String modifiedString = trimOrg(org); //private method to substring
if (modifiedString.length() == 4) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), modifiedString.charAt(modifiedString.length()-3), modifiedString.charAt(modifiedString.length()-4));
} else if (modifiedString.length == 3) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), modifiedString.charAt(modifiedString.length()-3), null);
} else if (modifiedString.length == 2) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), null, null);
} else if (modifiedString.length == 1) {
populateMap(modifiedString.charAt(modifiedString.length()-1), null, null, null);
}
} else {
LOG.error("Null org provided");
}
return map;
}
private static void populateMap(Map<String, Character> map, Character pos0, Character pos1, Character pos2, Character pos3) {
map.put("Position 3", pos3);
map.put("Position 2", pos2);
map.put("Position 1", pos1);
map.put("Position 0", pos0);
}
You could do something like this:
Runnable r = Arrays.asList(() -> {}, YourClass::doD, YourClass::doC, YourClass::doB, YourClass::doA, () -> {})
.get(Math.min(Math.max(0, org.length()), 4));
r.run();
But honestly, it's not worth it. Just use a switch.
Your question is strange because it appears to call the same doX() method every time. If that is really what you want, you can have a simple if-statement and supply it a range:
if(modifiedString.length() >= 1 && modifiedString.length() <= 4) {
doX();
}
If indeed you meant that they are different methods and do different things depending on the modifiedString.length value, you can use a switch-statement, as suggested by others:
switch (modifiedString.length()) {
case 1:
doA();
break;
case 2:
doB();
break;
case 3:
doC();
break;
case 4:
doD();
break;
default:
//if no case match
}

Alternate way for nested ifs using Boolean in Java

I have below block of code
if(Objects.nonNull(isMine)) {
if (isMine) {
this.books= // gets it from the database;
} else {
this. books= // gets it from the database
}
} else {
this. books = // gets it from the database
}
isMine - is a Boolean object
I tried with switch case by converting isMine to a string as below
String.valueOf(isMine)
But didn't work .Suggest a better and faster way to implement above code in java.
You can flatten your if-else statement by using else if:
if(isMine == null) {
books = allList;
} else if(isMine) {
books = myList;
} else {
books = notMyList;
}
Another approach would be to sperate the checks into methods:
public List<Book> getBookList(Boolean isMine) {
return isMine == null ? allList : getBookList(isMine.booleanValue());
}
public List<Book> getBookList(boolean isMine) {
return isMine ? myList : notMyList;
}
You can use Optional in this case:
Boolean isMine = null;
String str = "";
Optional<Boolean> optional = Optional.ofNullable(isMine);
str = optional.map(i -> i ? "a" : "b").orElse("c");
System.out.println(str);
So it will be something like:
this.books = optional.map(i -> i ? valForTrue : valForFalse).orElse(valForNull);
this.books = isMine != null ? (isMine ? this.myList : this.notMyList) : this.allList;
Using ternary operator inside of ternary operator e.g.
Do not even think about performance in your case, that's tiny.
Your current way looks good. And you have an answer with flatten way and nested ternary too.
If you still want to learn how to use switch in this case (please do not put this code in production. posting for showing you a way)
Correct way to achieve using String.valueOf(isMine) is
switch ( String.valueOf(isMine) ) {
case "null":
//TODO
break;
case "true":
//TODO
break;
case "false":
//TODO
break;
}
With pattern matching provided by vavr.io it can get very clean:
List<Books> output = Match(input).of(
Case($(true), dbCallX()),
Case($(false), dbCallY()),
Case($(), dbCallZ()));

How can I replace a switch in Java with a list that references a variable for each case?

I was unable to find a prior question like this here (which surprises me), so..
I have a working Java program where part of it analyzes typed input. Some input 'options' are the strings in the cases below.
switch (varName.toLowerCase()) {
case "steps":
common.steps = true;
break;
case "scale":
common.scale = true;
break;
case "float":
common.fracts = false;
break;
case "fraction":
common.fracts = true;
break;
case "spaces":
common.spaces = false;
break;
... etc.
}
In C or C++, I could shorten this code by making a list (which is a structure containing a string name and a variable pointer) such as
LIST varAction[] = { { "steps", &common.steps },
{ "scale", &common.scale },
.. etc.
};
and then simply checking in a loop with i = 0 thru size of the list
if ( strcmp(varAction[i].name, input) == 0) {
*varAction[i].pointer = condition;
}
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
I could use a hashed index into an array using the hash of the string, but that would prevent me from using the specific variable names thru the code as needed, making that code less clear... i.e. I don't want to do (pseudo-code)
hashTable[varName] instead of (for example)
if ( common.fracts )
{ do something }
There must be a better way? Is there? Thanks in advance.
From your question, it's fairly clear that you know you can't do what you've said you'd do in C/C++, but just for others coming to the question: Java doesn't have references to variables.
It's tempting to push the question out a level: Look at why you have varName in the first place and see if you can avoid it.
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
That suggests that common should have accessor function(s) for this information, so the switch exists only in one place (the getter) or two places (the getter and the setter).
void setThingy(String name, boolean value) {
switch (name.toLowerCase()) {
case "steps":
this.steps = value;
break;
case "scale":
this.scale = value;
break;
case "float":
this.fracts = value;
break;
case "fraction":
this.fracts = value;
break;
case "spaces":
this.spaces = value;
break;
// ... etc.
}
}
boolean getThingy(String name) {
switch (name.toLowerCase()) {
case "steps":
return common.steps;
case "scale":
return common.scale;
case "float":
return this.fracts;
case "fraction":
return this.fracts;
case "spaces":
return this.spaces;
// ... etc.
}
}
If common's class isn't something you can change, a static utility function somewhere would also work, but better if it's in the class if possible.
With Java 8+ you could use something like:
Map<String, Runnable> actions = new HashMap<> ();
actions.put("steps", () -> common.steps = true);
actions.put("scale", () -> common.scales = true);
//etc.
then in your code:
actions.get(varName.toLowerCase()).run(); //need null check
You could do it with Java 7- too using anonymous classes but it would be more verbose.
Here’s an option, developing my idea from the comment just a little bit. Not sure whether you will like it, I’d like to offer it in case.
public class Common {
private Map<String, Boolean> options = new HashMap<>();
public void setOption(String varName, boolean condition) {
options.put(varName.toLowerCase(), condition);
}
public boolean isSteps() { return options.get("steps"); }
public boolean isFracts() { return options.get("fractions"); }
public boolean isScale() { return options.get("scale"); }
}
You may want to put in some defense, for instance to avoid setting non-existing options.
Edit: Drawing on David Foerster’s comments on enums, here’s a solution using them:
public enum Option {
steps, scale, fraction;
private boolean option = false;
public static void setOption(String varName, boolean condition) {
valueOf(varName.toLowerCase()).option = condition;
}
public boolean isSet() {
return option;
}
}
Now the lookup happens in the setter, not in the getter. Defence against setting non-existing options is built-in: you will get an exception if you try, this behaviour can of course be modified if you prefer. The solution is quite extensible, it’s easy to add more enum constants if the need arises.
Warning: It's been a while since I last wrote some Java, and this is probably against best practices, so continue with care! Also it's just a quick and dirty example, I wrote this on a (not up to date) mobile phone...
You could try to use reflection:
class Common {
public boolean a;
public boolean b;
public boolean tryToSet(String field, boolean value) throws java.lang.Exception {
Class<?> cl = this.getClass();
try {
Field f = cl.getDeclaredField(field);
f.setBoolean(this, value);
return true;
} catch(NoSuchFieldException e) {
return false;
}
}
}
Returning a boolean gives you the possibility to implement a "default case":
if (! c.tryToSet("x", false)) {
System.out.println("some default case");
}
Try this:
import java.util.Scanner;
public class TestCases
{
static boolean steps = false;
static boolean fracts;
static boolean scale;
public static void main( String[] args )
{
Scanner input = new Scanner( System.in );
System.out.println( "Type the input" );
String typedInput = input.nextLine();
Object[][] tests = { { "steps", steps }, { "float", fracts }, { "scale", scale } };
for( int i = 0; i < tests.length; i++ )
{
if( typedInput.equals( tests[ i ][ 0 ] ) )
{
tests[ i ][ 1 ] = true;
break;
}
}
for( int i = 0; i < tests.length; i++ )
{
for( int j = 0; j < tests[ i ].length; j++ )
{
System.out.print( tests[ i ][ j ] + " " );
}
System.out.println();
}
}
}
All necessary conversions are automatically done.

Comparing Using 2 Properties in Ascending and Descending Orders

I have an object that has multiple properties, two of which the user can choose to order by, both can be Ascending, Descending, or neither (Normal), and they are independent of each other. So my cases are:
Case 1
propA - Normal
propB - Normal
Case 2
propA - Asc
propB - Normal
Case 3
propA - Desc
propB - Normal
And you get the idea. I'm using a Comparator to do this, and so far I have been able to get it to sort when one or both values are set to Normal. The part that I'm unsure of is what to do when I have chosen to sort by both methods. For example, if I want to order by propA ascending and propB descending, it should look a little like this
propA propB
A Z
A D
B M
B A
R Q
Z Z
Z A
Here is how I'm sorting now
#Override
public int compare(Field lhs, Field rhs) {
switch (growerSort) {
case NORMAL:
switch (fieldSort) {
case NORMAL:
return ((Integer) lhs.getID()).compareTo(rhs.getID());
case ASC:
return lhs.getPropB().toLowerCase().compareTo(rhs.getPropB().toLowerCase());
default:
return rhs.getPropB().toLowerCase().compareTo(lhs.getPropB().toLowerCase());
}
case ASC:
switch (fieldSort) {
case NORMAL:
return lhs.getPropA().toLowerCase().compareTo(rhs.getPropA().toLowerCase());;
case ASC:
return 0; // 0 used as placeholder
default:
return 0; // 0 used as placeholder
}
default:
switch (fieldSort) {
case NORMAL:
return rhs.getPropA().toLowerCase().compareTo(lhs.getPropA().toLowerCase());
case ASC:
return 0; // 0 used as placeholder
default:
return 0; // 0 used as placeholder
}
}
}
How can I sort with two different fields, each with their own order of sorting?
I'm a little bit confused of your Comparator. It's not easy to understand what switch triggers what event.
However I'll describe the standard procedure.
You'll need a priority order over your fields you want to compare. In your example above, I assume it first must be sorted by propA, then by propB.
Then you first sort by propA. If it returns "equals" (zero), then you want to sort by the next field, propB, and so on.
Let me show you an example:
#Override
public int compare(final Field lhs, final Field rhs) {
int firstCompareValue = lhs.getPropA().compareTo(rhs.getPropA());
if (firstCompareValue == 0) {
// lhs and rhs are equals in propA, use propB
int secondCompareValue = lhs.getPropB().compareTo(rhs.getPropB());
return secondCompareValue;
} else {
return firstCompareValue;
}
}
Of course you can also do this iterative if you have multiple fields, as long as you have specified an order (e.g. by using an ordered list over your property fields).
Now you need to add your switches to this showcase :) I'll recommend doing a PropertyComparator for that.
public final class PropertyComparator extends Comparator<Comparable<?>> {
private final boolean mUseDscOrder = false;
public void setUseDscOrder(final boolean useDscOrder) {
mUseDscOrder = useDscOrder;
}
public int compare(final Comparable<?> o1, final Comparable<?> o2) {
if (!mUseDscOrder) {
return o1.compareTo(o2);
} else {
// Reverses the logic, results in DscOrder
return o2.compareTo(o1)
}
}
}
And now use it in the above Comparator.
#Override
public int compare(final Field lhs, final Field rhs, final boolean firstUseDscOrder, final boolean secondUseDcsOrder) {
PropertyComparator firstComparator = new PropertyComparator();
firstComparator.setUseDscOrder(firstUseDscOrder);
int firstCompareValue = firstComparator.compare(lhs.getPropA(), rhs.getPropA());
if (firstCompareValue == 0) {
// lhs and rhs are equals in propA, use propB
PropertyComparator secondComparator = new PropertyComparator();
secondComparator.setUseDscOrder(secondUseDscOrder);
int secondCompareValue = secondComparator.compare(lhs.getPropB(), rhs.getPropB());
return secondCompareValue;
} else {
return firstCompareValue;
}
}
I've not tested it but I think you get the idea :)
Create 1 comparator that sorts on the "first field". If the values of the first field are equal, sort on the "second field".
if(object1.f1.equals(object2.f1)){
object1.f2.compareTo(object2.f2);
} else {
object1.f1.compareTo(object2.f1);
}

Advanced Java enums in Swift

I have a number of Java classes I need to convert to Swift code.
One of the classes has an advanced enum:
public enum Student {
STUDENT_ONE("Steve", "Jobs")
STUDENT_TWO("Tim", "Cook")
private String _firstName;
private String _lastName;
}
How can I replicate the same behavior in Swift?
After some thought, I agree with godmoney that aksh1t's solution is better that my solution using Strings.
Anyway, here is a more concise variant of aksh1t's solution, using only one computed property returning a tuple: (tested in Swift 2.0)
enum Student {
case STUDENT_ONE, STUDENT_TWO
typealias Details = (firstName: String, lastName: String)
var details : Details {
switch(self) {
case STUDENT_ONE : return ("Steve", "Jobs")
case STUDENT_TWO : return ("Tim", "Cook")
}
}
}
// Usage:
func test(sd: Student.Details) {
print(sd.firstName)
print(sd.lastName)
}
test(Student.STUDENT_ONE.details)
I was trying to do the same thing with converting Java code to Swift, and ended up doing something like this :
public enum Student {
case STUDENT_ONE
case STUDENT_TWO
var firstName: String {
get {
switch self {
case .STUDENT_ONE:
return "Steve"
case .STUDENT_TWO:
return "Tim"
}
}
}
var lastName: String {
get {
switch self {
case .STUDENT_ONE:
return "Jobs"
case .STUDENT_TWO:
return "Cook"
}
}
}
}
Now, this is really long and messy and I'm not really sure whether this is the right way to do it, but I couldn't find anything else that worked. I would love to know if there is some other better way to do it.
This is what I ended up doing - not sure about this at all:
struct Students {
enum Students {
case STUDENT_ONE(String, String)
case STUDENT_TWO(String, String)
}
let STUDENT_ONE = Students.STUDENT_ONE("Steve", "Jobs")
let STUDENT_TWO = Students.STUDENT_TWO("Steve", "Two")
}
Enums are not necessarily the best choice to represent this type of data. I choose structs and this works well, using the correct accessors:
public struct Student {
public let firstName : String
public let lastName : String
public static let STUDENT_ONE = Student(firstName: "Steve", lastName: "Jobs")
public static let STUDENT_TWO = Student(firstName: "Tim", lastName: "Cook")
}
Moved here from another question marked as a duplicate so the variable names don't match up exactly, however, the concepts all do.
The most obvious way would be:
public enum EnumWeapon {
case WOODEN_SWORD
case STONE_SWORD
case STEEL_SWORD
func getName() -> String {
switch self {
case WOODEN_SWORD: return "Wooden Sword"
case STONE_SWORD: return "Stone Sword"
case STEEL_SWORD: return "Steel Sword"
}
}
func getDamage() -> Int {
switch self {
case WOODEN_SWORD: return 4
case STONE_SWORD: return 6
case STEEL_SWORD: return 8
}
}
}
If you have a single value to associate with each enum case, you can use the raw value syntax, or just use it to simplify the enum case above:
public enum Weapon : Int {
case WOODEN_SWORD = 4
case STONE_SWORD = 6
case STEEL_SWORD = 8
func getDamage() -> Int {
return rawValue
}
func getName() -> String {
switch self {
case .WOODEN_SWORD: return "Wooden Sword"
case .STONE_SWORD: return "Stone Sword"
case .STEEL_SWORD: return "Steel Sword"
}
}
}
Obviously, if you don't need the name, you can omit the getName function. Likewise you can omit the getDamage function and just use weapon.rawValue
An even simpler way, and yet more analogous to the actual Java implementation, would be to use a struct instead of an enum, as:
public struct Weapon {
public let name : String
public let damage : Int
private init(name:String, damage:Int) {
self.name = name
self.damage = damage
}
public static let WOODEN_SWORD = Weapon(name: "Wooden Sword", damage: 4)
public static let STONE_SWORD = Weapon(name: "Stone Sword", damage: 6)
public static let STEEL_SWORD = Weapon(name: "Steel Sword", damage: 8)
}
and, be redefining operator ==, you can get equality comparisons:
func == (lhs:Weapon, rhs:Weapon) -> Bool {
return lhs.name == rhs.name && lhs.damage == rhs.damage
}
and, by redefining operator ~= you can get switch to work as expected:
func ~= (lhs:Weapon, rhs:Weapon) -> Bool {
return lhs == rhs
}
func test(sword:Weapon) {
switch sword {
case Weapon.STONE_SWORD: print("stone")
default: print("something else")
}
}
test(Weapon.STONE_SWORD)
A whole lot of options, mostly it just depends on what you're really trying to do and how much data you need to wrap in the enum.

Categories

Resources