I want to know if is it possible to Store a String variable on a String array?
I cant explain it well but here is what i do:
String st1 = "",st2 = "",st3 = "",st4 = "";
String[] str = {st1,st2,st3,st4};
Unfortunately when i use for loop the str gets the value of st1 and st2 and st3 ans st4 not the variable it self..
This is what i want to do exactly on my mind..
Whenever a have a String array for example:
String[] containsValue = { "hi", "hello", "there" };
String strHi, strHello, strThere;
String[] getContainsValue = { strHi, strHello, strThere };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x] = containsValue[x];
}
The value of:
strHi = "hi"
strHello = "hello"
strThere = "there";
Basically i want to transfer that value of containsValue[] to 3 String which is strHi, strHello, strThere that are stored in getContainsValue[]. Then use for loop to asign value to them came from containsValue[].
Is this posible? If so then can you give me some format how to do it? thanks..
You can use Map<K,V>.
Map<String,String> map=new HashMap<String,String>();
map.put("strHi","hi");
map.put("strHello","hello");
map.put("strThere","there");
System.out.println(map.get("strHello"));
You can use enum class as the Array needed :
public enum EnumModifE {
str1("1"), str2("2"), str3("3");
String value;
EnumModifE(final String s) {
this.value = s;
}
public void setValue(final String s) {
this.value = s;
}
}
public class EnumModifM {
public static void main(final String[] args) {
for (final EnumModifE eme : EnumModifE.values()) {
System.out.println(eme + "\t" + eme.value);
}
EnumModifE.str1.setValue("Hello");
EnumModifE.str2.setValue("all");
EnumModifE.str3.setValue("[wo]men");
for (final EnumModifE eme : EnumModifE.values()) {
System.out.println(eme + "\t" + eme.value);
}
}
}
Output
str1 1
str2 2
str3 3
str1 Hello
str2 all
str3 [wo]men
See in Effective Java use of enum
The concept you are looking for is an "l-value". Briefly, when you are using a variable, are you using the value contained in the variable, or are you talking about the variable itself so that you can store something else into it? You want array that you're calling getContainsValue to have l-values for strHi, strHello, and strThere. Unfortunately there is no way to do this in Java. Initializing getContainsValue with strHi, strHello, and strThere uses the values of those variables, not their l-values.
Let's step back a bit and talk more about l-values vs values (sometimes, r-values). Consider the following code snippet:
int i = 17;
i = i + 1;
That second line is obviously not an equation; that would be nonsensical. Instead, it is an assignment. The meaning of i on the left and right sides of an assignment is different. On the right hand side, i means to use the value of that variable, in this case 17. On the left hand side, i means the variable itself, as a destination for storing values. Even though they look the same, the use of i on the right-hand side is for its value (more specifically, its r-value) and the use of i on the left-hand side is for its l-value.
In Java, there is no way to express the l-value of a variable in an array initializer, so what you're trying to do doesn't work. As others have pointed out, in other languages like C this is possible, by using the & (address-of) operator.
Since Java has limited ways of expressing l-values, usually the concept of "a place to store something into" is expressed via a reference to an object. One can then use this reference to store into fields of that object or to call methods on that object.
Suppose we have a class like this:
class MyContainer {
String str;
void setString(String s) { str = s; }
String getString() { return str; }
}
We could then rewrite your code to do something like the following:
String[] containsValue = { "hi", "hello", "there" };
MyContainer hiCont = new MyContainer();
MyContainer helloCont = new MyContainer();
MyContainer thereCont = new MyContainer();
MyContainer[] getContainsValue = { hiCont, helloCont, thereCont };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x].setString(containsValue[x]);
}
Well you can use this.
Map<String,String> map = new HashMap<String,String>();
String[] str = {"hi","hello","there"};
for(int x = 0; x < str.lenght;x++){
map.put(str[x],"something you want to store");
}
Best thing may be use Map and store as key-Value pairs.
Map<String,String> myKVMap=new HashMap<String,String>();
myKVMap.put("strHi","value1");
myKVMap.put("strHello","value2");
myKVMap.put("strThere","value3");
This way you can eliminate all the variable name and value issues.
I think you should use Collection like Map.
Map is used to store data in the form of Key-Value Pairs.
Assume the Key is String and Value is a String too in your case.
Map<String, String> mp = new Map<String, String>();
mp.put("str1","Hi");
mp.put("str2","Hello");
You can iterate over it like the below.
for(Map.Entry<String, String> ar : mp.entrySet()){
System.out.println("Key: "+ar.getKey()+" :: "+"Value: "+ar.getValue());
}
Using a Map is a good idea. Another approach is to instantiate class variables, then assigning values will work.
public void testTransfer() {
String containsValue[] = { "hi", "hello", "there" };
Data strHi = new Data();
Data strHello = new Data();
Data strThere = new Data();
Data[] getContainsValue = { strHi, strHello, strThere };
for (int x = 0; x < getContainsValue.length; x++) {
getContainsValue[x].value = containsValue[x];
}
// print out
System.out.println(strHi.value);
System.out.println(strHello.value);
System.out.println(strThere.value);
}
class Data {
private String value;
}
There is no simple way to do what you want to do in Java. What you would need is the equivalent of the C / C++ address-of operator (&) ... or maybe Perl's ability to use a string as a variable name. Neither of these are supported in Java.
In theory, if the variables where instance variables, you could use reflection to access and update them. But the code to do this is messy, inefficient and fragile. And it won't work with local variables.
You would be better off looking for a different solution to the problem; e.g. use a Map, as other answers have suggested.
Or just settle for some clunky (but robust and reasonably efficient) code that uses a switch or series of if else if tests and the original variables.
If I am understanding your question, you want to be able to assign a regular String variable by looking it up in an array first and then making the assignment.
I agree with the other responders that if you are finding this approach necessary, it is probably ill-advised. But in the spirit of pure Q&A, here's the way:
interface StringAssigner {
void assign( String strValue );
}
// ...
String strHi, strHello, strThere;
StringAssigner[] asaGetContainsValue = {
new StringAssigner() { #Override public void assign( String strValue ) { strHi = strValue; } },
new StringAssigner() { #Override public void assign( String strValue ) { strHello = strValue; } },
new StringAssigner() { #Override public void assign( String strValue ) { strThere = strValue; } }
};
// ...
for (int x = 0; x < asaGetContainsValue.length; x++) {
asaGetContainsValue[x].assign( containsValue[x] );
}
Just say no.
I do agree with the other answers here that this feels like a workaround for something, but without knowing what that something is I cannot suggest anything better.
To answer the question, though: you could, however, wrap the string in simple class and store the object references of that class in your array and strHi, strHello, and strThere. This way even when you change the string property inside the class, the class object itself does not change so you will see the behavior you are looking for.
Or, you can use a HashMap as others have suggested. In your case if you still want to use the getContainsValue array, you can store the keys:
Map<String,String> map = new HashMap<String,String>();
map.put("strHi","");
map.put("strHello","");
map.put("strThere","");
String[] containsValue = { "hi", "hello", "there" };
String[] getContainsValue = { "strHi", "strHello", "strThere" };
for (int x = 0; x < getContainsValue.length; x++) {
map.put(getContainsValue[x], containsValue[x]);
}
Then, map.get("strHi") would return "hi" as you expect.
Related
I'm creating a java scraping program using selenium and inserting the data into a database. I'm actively looking to improve my skillset but I don't find instructional videos too helpful since I lose interest, but I really enjoy learning through doing. This code below works as needed, but it looks really really ugly and I feel there must be a better/cleaner solution. For reference it builds a comma separated string with data such as "Value1", or "Value1, Value2", etc depending on the keyword count. My original logic was outputting ", Value1, Value2" which is why I added the "if (x ==0)" logic. I have a lot of methods that are just sloppy like this, so any pointers for improving my code is appreciated, thanks!
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
public ArrayList<String> keywordChecker(String title) {
ArrayList<String> keywordList = new ArrayList<String>();
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
String[] keywordTextCombinations = { "Value1", "Value2", "Value3", [imagine a list of 20 items]};
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())) {
keyword1 = keywordTextCombinations[i];
keywordList.add(keyword1);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword2 = keywordTextCombinations[i];
keywordList.add(keyword2);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword3 = keywordTextCombinations[i];
keywordList.add(keyword3);
break;
}
}
return keywordList;
}
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
This will:
Create a new variable, named keywords, that can point at arraylists.
Makes a new arraylist object.
Assigns the reference to this newly created object to the keywords variable.
Then tosses that reference away and makes that created object instant garbage, as you then immediately assign some other reference to it.
In other words, that new ArrayList<String>(); does nothing whatsoever but waste time and space. Get rid of it. Let's also be like other java coders and use the most general type that we're interested in. For beginners, that basically means, 'the variable should be of type List, not ArrayList. It's good to write code in similar style to other java coders; makes it easier to read their code and it makes it easier for them to read your code.
List<String> keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
You're getting a single keyword and you call this list? Names are important. When they lie, your code becomes unreadable.
You're turning a list of strings into a single string with all the values, separated by a comma. That sounds like a common job. When something sounds common enough, search the web. You'll usually find that there's a one-liner. So it is here:
keywordValues.add(String.join(", ", keywords));
Oof, that's way less code.
The keywordChecker method
It helps to document code, especially when asking for help. Evidently, this method is to scan the provided title variable, and search for any of a list of keywords, then it is to return each matching keyword. However, you've limited to return at most 3. I assume you didn't want that. But if you do, I'll show you how, with a one-liner of course.
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
When you start naming variables like this, stop. There's no way that's correct. Think for a moment. You're already using them, you know how to do this properly: Lists. Once you use a list, this becomes near trivial. Also, method names should generally be a verb; common java style. Let's also make constants, well, constant. Let's also avoid arrays, they are unwieldy and annoying.
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) out.add(keyword);
}
return out;
}
That eliminated a ton of lines, that's nice. If you want to return no more than 3 keywords at most... all you need to do is abort looping when you're 'full'. As last line within the for loop:
if (out.length() == 3) break;
Putting it all together:
keywordValues.add(String.join(", ", findMatchingKeywords(title)));
...
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) {
out.add(keyword);
if (out.length() == 3) break;
}
}
return out;
}
You can try to do everything in one for loop. Also, I recommend that you use a HashSet since you are comparing elements. A HashSet cannot contain duplicate elements, so if you try to add an element that already exists it doesn't do it and it returns false (Yes, the add function in HashSet returns a boolean).
Example code:
int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;
Now, say I want to have the user input a string:
String input = new Scanner(System.in).nextLine();
Then, say the user inputs potato. How would I retrieve the variable named potato and do stuff with it? Something like this:
System.getVariable(input); //which will be 2
System.getVariable("stackOverflow"); //should be -4
I looked up some things and did not find much; I did find a reference to something called "the Reflection API," but that seems too complicated for this one simple task.
Is there a way to do this, and if so, what is it? If "Reflection" does indeed work and if it is the only way, then how would I use it to do this? The tutorial page for it has all sorts of internal stuff that I can't make any sense of.
EDIT: I need to keep the Strings in the variables for what I am doing. (I can't use a Map)
Using reflection doesn't seem like a good design for what you're doing here. It would be better to use a Map<String, Integer> for example:
static final Map<String, Integer> VALUES_BY_NAME;
static {
final Map<String, Integer> valuesByName = new HashMap<>();
valuesByName.put("width", 5);
valuesByName.put("potato", 2);
VALUES_BY_NAME = Collections.unmodifiableMap(valuesByName);
}
Or with Guava:
static final ImmutableMap<String, Integer> VALUES_BY_NAME = ImmutableMap.of(
"width", 5,
"potato", 2
);
Or with an enum:
enum NameValuePair {
WIDTH("width", 5),
POTATO("potato", 2);
private final String name;
private final int value;
private NameValuePair(final String name, final int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
static NameValuePair getByName(final String name) {
for (final NameValuePair nvp : values()) {
if (nvp.getName().equals(name)) {
return nvp;
}
}
throw new IllegalArgumentException("Invalid name: " + name);
}
}
Variable names are only available at compiler time. Reflection only gives access to class declarations and items declared inside them, but not to local variables. I suspect that a Map of some kind will be a more appropriate solution to your real problem. Specifically, check out HashMap and TreeMap.
Instead of trying to find the value of a variable name, why don't you use a Map with a key/value pair?
Map<String, Integer> vars = new HashMap<String, Integer>();
vars.put("width",5);
vars.put("area",8);
vars.put("potato", 2);
vars.put("stackOverflow",-4);
Then you could access the inputs like so:
vars.get(input); //would be 2
vars.get("stackOverflow"); //would be -4
I have another solution without a map :
class Vars {
Integer potato, stack;
public Vars(a,b) {
potato=a;
stack=b;
}
}
Object object=(Object)new Vars(1,2);
Class<?> c = object.getClass();
Integer result=(Integer)c.getField("potato").get(object);
I have a solution for this problem that does not involve using a map. I ran into this technique because we had several variables that needed to be update based on something within the variable name itself. However, the best way to do this is by using the getters/setters rather than the variables.
After you create your class, you can access the methods by creating Method objects and invoking them individually.
public class FooClass
private String foo1;
private String foo2;
public String getFoo1();
public String getFoo2();
FooClass fooClass = new FooClass();
Method mFoo1 = fooClass.getClass().getMethod("getFoo" + increment + "()");
mFoo1 .invoke(fooClass);
However, this would not be limited to only incremental numbers, as long as you can get the string to match the method exactly.
String value = "Potato";
Method mPotato = myClass.getClass().getMethod("get" + value+ "()");
mPotato.invoke(myClass);
Very redundant, but you can keep your variable names when using a map:
int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;
Map<String, Integer> map = new HashMap<>();
map.put("width", width);
map.put("area", area);
map.put("potato", potato);
map.put("stackOverflow", stackOverflow);
But a statement like this:
width = 42;
would not change the value in the Map:
String input = "width";
map.get(input); // <-- still returns 5.
Only a new call of put fixes that:
width = 42;
map.put("width", width);
// or
map.put("width", 42);
I have a class declared to hold information. Let's say it has these fields
class data {
int a;
int b;
int c;
}
And I want to access these fields like this:
String [] fields = {"a", "b", "c"};
data da = new data();
for (int i = 0; i < 3; i++)
if (da.fields[i] < 10)
dosomething();
Is there any way in Java to do this? Googling, I got some results about something called "reflection, " but I've never really heard of that, and I don't think it's quite what I want. Is there any way to do this in Java? If not, are there any languages that support this kind of thing (just out of curiosity)?
Reflection is probably what you need. But what you need more is a hard look at your design. You should avoid reflection where possible.
If you are still interested in doing this, take a look at Java Reflection: Fields.
Field field = aClass.getField("someField");
Is what you would do to get the field by that name. A more detailed example of what you want.
Class aClass = MyObject.class
Field field = aClass.getField("someField");
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objetInstance, value);
You could add a suitable API to your class:
class data {
int a;
int b;
int c;
int get(String field) {
if (field.equals("a")) return a;
if (field.equals("b")) return b;
if (field.equals("c")) return c;
throw new IllegalArgumentException();
}
}
Then you could:
String [] fields = {"a", "b", "c"};
data da = new data();
for (int i = 0; i < 3; i++)
if (da.get(fields[i]) < 10)
dosomething();
Reflection is the way to go. Karthik T has the correct answer.
Without using reflection:
Declare the fields to be an array (or a Map), and the names as lookups:
class data {
int[] fields = new int[3];
public static final int A = 0;
public static final int B = 1;
public static final int C = 2;
}
public void foo() {
data da = new data();
int[] fields = {data.A, data.B, data.C};
for (int n : fields) {
if (da.fields[n] < 10) doSomething();
}
}
Its ugly, and your design is probably wrong if you want to do something like this, but it works.
You don't really say what's your real problem; so it's hard to say if using reflection or something else is what you need. However, when someone talk about associating a string value with another variable, what they often need to use is a Map (or a dictionary in other languages); something along the line of:
TreeMap<String, Integer> tm = new TreeMap<String, Integer>();
tm.put("a", 1);
tm.put("b", 2);
tm.put("c", 3);
for (String k: tm.keySet()) {
System.out.println(k + ": " + tm.get(k));
}
I am new to Java. I want to Parse the data which is in this Format
Apple;Mango;Orange:1234;Orange:1244;...;
There could be more than one "Orange" at any point of time. Numbers (1,2...) increase and accordingly as the "Orange".
Okay. After splitting it, Lets assume I have stored the first two data(Apple, Orange) in a variable(in setter) to return the same in the getter function. And now I want to add the value(1234,1244....etc) in the 'orange' thing into a variable to return it later. Before that i have to check how many oranges have come. For that, i know i have to use for loop. But don't know how to store the "Value" into a variable.
Please Help me guys.
String input = "Apple;Mango;Orange:1234;Orange:1244;...;"
String values[] = input.split(";");
String value1 = values[0];
String value2 = values[1];
Hashmap< String, ArrayList<String> > map = new HashMap<String, ArrayList<String>>();
for(int i = 2; i < values.length; i = i + 2){
String key = values[i];
String id = values[i+1];
if (map.get(key) == null){
map.put(key, new ArrayList<String>());
}
map.get(key).add(id);
}
//for any key s:
// get the values of s
map.get(s); // returns a list of all values added
// get the count of s
map.get(s).size(); // return the total number of values.
Let me try to rephrase the question by how I interpreted it and -- more importantly -- how it focuses on the input and output (expectations), not the actual implementation:
I need to parse the string
"Apple;Mango;Orange:1234;Orange:1244;...;"
in a way so I can retrieve the values associated (numbers after ':') with the fruits:
I should receive an empty list for both the Apple and Mango in the example, because they have no value;
I should receive a list of 1234, 1244 for Orange.
Of course your intuition of HashMap is right on the spot, but someone may always present a better solution if you don't get too involved with the specifics.
There are a few white spots left:
Should the fruits without values have a default value given?
Should the fruits without values be in the map at all?
How input errors should be handled?
How duplicate values should be handled?
Given this context, we can start writing code:
import java.util.*;
public class FruitMarker {
public static void main(String[] args) {
String input = "Apple;Mango;Orange:1234;Orange:1244";
// replace with parameter processing from 'args'
// avoid direct implementations in variable definitions
// also observe the naming referring to the function of the variable
Map<String, Collection<Integer>> fruitIds = new HashMap<String, Collection<Integer>>();
// iterate through items by splitting
for (String item : input.split(";")) {
String[] fruitAndId = item.split(":"); // this will return the same item in an array, if separator is not found
String fruitName = fruitAndId[0];
boolean hasValue = fruitAndId.length > 1;
Collection<Integer> values = fruitIds.get(fruitName);
// if we are accessing the key for the first time, we have to set its value
if (values == null) {
values = new ArrayList<Integer>(); // here I can use concrete implementation
fruitIds.put(fruitName, values); // be sure to put it back in the map
}
if (hasValue) {
int fruitValue = Integer.parseInt(fruitAndId[1]);
values.add(fruitValue);
}
}
// display the entries in table iteratively
for (Map.Entry<String, Collection<Integer>> entry : fruitIds.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
}
}
If you execute this code, you will get the following output:
Mango => []
Apple => []
Orange => [1234, 1244]
I'm working in java, and I have a method that returns a pair, ie. (String, integer). At a different point in the program, I want to pull out the String alone. How do I do that?
Thanks.
add another method returning the String only and use that at the mentioned different point in your program
If you build an object, you can easily get a value from object like getString() (private case) : newString = p1.getString ;
How are you returning a pair? It might be with an object, or an array.
If it's an object you're returning, it probably looks like this...
public ResultObject MyMethod() {
String s = "foo";
int i = 42;
return new ResultObject(s, i);
}
public class ResultObject() {
public String s;
public int i;
public ResultObject(String s, int i) {
this.s = s;
this.i = i;
}
}
And you can access the result like this
ResultObject r = MyMethod();
System.out.println(r.s); // "foo"
System.out.println(r.i); // "42"
If it's an array you're returning, it probably looks like this...
public Object[] MyMethod() {
String s = "foo";
int i = 42;
return new Object[] { s, i };
}
And you can access the result like this
Object[] r = MyMethod();
System.out.println(r[0]); // "foo"
System.out.println(r[1]); // "42"
Returning a result object is preferable, because the array causes you to rely on the order of the results, is less descriptive when you access the result objects (r[0] versus r.somename), is prone to out-of-bounds exceptions, and is not typed (you'll have to cast your result objects to the type they're supposed to be).
Object[] method(int param1, int param2){
//do something
return new Object[]{"string", 1};
}
....
String value = (String)obj.method(param1, param2)[0];
For more than a return using a Map in return.
Para mais de um retorno utilize um Map como retorno.
public Map<String, Integer> method(){
Map<String,Integer> map = new HashMap<String, Integer>();
String s = "foo";
Integer i = 99;
map.put(s,i);
return map;
}