I'm very new to Java and I'm running into difficulty with something simple. I create a vector like the below, where the third element is an array of Strings, not a String itself.
this.myvec = new Vector();
myvec.add("a");
myvec.add("b");
myvec.add(new String[]{
"c",
"d",
"e",
"f");
Later I want to iterate over this, but because some elements are Strings and some are String arrays, I have to do it like this. But I also want to log it, so I have a condition based on the type to send to different log statements.
However in the case of the array, I want to join it as you can see below.
for (Object myobj : myvec) {
if (myobj.getClass().equals(String.class)) {
log.info("My object is " + myobj);
}
else {
log.info("My object is " + String.join(",", myobj));
}
The second log statement doesn't compile because you can't have an Object be the second argument to String.join. How can I get this to work?
If you really want to have mixed types in your Vector you can do it this way, using the instanceof keyword:
Vector<Object> myvec = new Vector<>();
myvec.add("a");
myvec.add("b");
myvec.add(new String[] {"c", "d", "e", "f"});
myvec.add(1); // Added to test the Unknow type object
for (Object myobj : myvec) {
String myobjAsString = "Unknown"; // default
if (myobj instanceof String) {
myobjAsString = (String)myobj;
} else if (myobj instanceof String[]) {
String[] myarray = (String[])myobj;
myobjAsString = String.join(",", myarray);
}
System.out.println("My object is " + myobjAsString);
}
Prints out:
My object is a
My object is b
My object is c,d,e,f
My object is Unknown
Side notes:
Declare your Vector as a Vector of Objects: Vector<Object>. It is a Generic class. See Vector Api and Generic Types
Vector is only preferred in very specific cases (so specific that I can't think of one), I don't think you should be bothered with that at your level, you might prefer to use ArrayLists<T> in most if not all cases. See Vector Vs ArrayList
To use an ArrayList instead of a Vector, simply declare:
List<Object> myvec = new ArrayList<>();
The rest of the code is the same.
Try this
log.info("My object is " + String.join(",", (String[])myobj));
Related
Input:
I have a List abcLines which has all types of lines of type A or B or C.
I also have a readymade List of type A (aLines).
I want to separate the big list (abcLines) into 3 different lists (aLines, bLines and cLines).
class ABCLine {
int id;
Object tlId; // value of this field is false (if the line type is A or C) or the value of this field is a List (if the type is B)
}
List<ABCLine> bLines = new ArrayList<ABCLine>();
List<ABCLine> cLines = new ArrayList<ABCLine>();
abcLines.forEach(abcLine -> {
if (abcLine.tlId instanceof List) {
bLines.add(abcLine);
abcLines.remove(abcLine);
} else {
aLines.forEach(aLine -> {
if (aLine.id.equals(abcLine.id)) {
abcLines.remove(abcLine);
}
});
}
});
cLines = abcLines;
How can I write this code using Java 8 streams in a better way?
Here's a solution that uses Collectors.partitioningBy to separate the lines.
List<ABCLine> aLines = new ArrayList<>(); //Ready made aline list
List<ABCLine> abcLines = new ArrayList(); // list that contains the A B and C lines.
//1. We first separate the b lines from the a and c lines by checking whether the field `tlId` of an instance is a `List` or not. We use `Collectors.partitioningBy` to partition the instances based on this condition. The end result is a map holding two lists that can be retrieved with the keys `true` and `false`.
Map<Boolean, List<ABCLine>> partitionedLines = abcLines.stream().collect(Collectors.partitioningBy(abcLine -> abcLine.tlId instanceof List));
//2. Retrieve the B lines from the map.
List<ABCLine> separatedBLines = partitionedLines.get(true);
//3. Retrieve the A and C lines from the map.
List<ABCLine> aAndCLines = partitionedLines.get(false);
//4. Make a Set containing all the `id` field values from the ready made aline list that you mentioned. This Set will be used to partition the a lines from the c lines.
Set<Integer> aLineIds = aLines.stream().map(aLine -> aLine.id).collect(Collectors.toSet());
//5. We use `Collectors.partitioningBy` again to partition/separate the A lines from the C lines using `aLineIds.contains(line.id)` as the condition. Because the type of the aList id collection is a set we can determine very fast whether the `id` of `line` equals any of the ids in the set.
Map<Boolean, List<ABCLine>> aAndCMap = aAndCLines.stream().collect(Collectors.partitioningBy(line -> aLineIds.contains(line.id)));
//6. Now you only have to retrieve the A and C lines from the map and you're done.
List<ABCLine> separatedALines = aAndCMap.get(true);
List<ABCLine> separatedCLines = aAndCMap.get(false);
Here is the Java code to find the shortest concatenation of elements of Array wordBank to construct String Terget, using Dynamic Programming.
Example:
Input: wordBank = {"ab", "c", "d", "abc", "ad"},
Target = "abcd".
Output: {"abc", "d"}.
To do this, I have stored the combination of elements as an ArrayList in a HashMap.
However, the hashMap does not store the values correctly, i.e., the values change when I recursively call the function, although I have cloned the ArrayList before adding it to the map.
Any idea why this happens?
The code works well with arrays.
static ArrayList<String> bestConstruct(String target, String[] wordBank, HashMap<String, ArrayList<String>> map) {
if(target.isEmpty())
{
return new ArrayList<String>();
}
if(map.containsKey(target))
return map.get(target);
ArrayList<String> shortestCombination = null;
for (String word : wordBank) {
if(target.startsWith(word)) {
String newTarget = target.substring(word.length(), target.length());
ArrayList<String> combination = bestConstruct(newTarget, wordBank, map);
if(combination != null) {
combination.add(word);
if(shortestCombination == null || combination.size() < shortestCombination.size())
shortestCombination = (ArrayList<String>)(combination.clone());
}
}
}
map.put(target, (ArrayList<String>) (shortestCombination.clone()));
return shortestCombination;
}
The problem is the interaction between these lines:
if(map.containsKey(target))
return map.get(target);
and
ArrayList<String> combination = bestConstruct(newTarget, wordBank, map);
if(combination != null) {
combination.add(word);
If you return the memoized list, you're updating it before you clone it.
In general, don't rely on callers to "do the right thing": if you don't want the list in the map to be updated, do the copy yourself before you return it:
if(map.containsKey(target))
return new ArrayList<>(map.get(target));
You may also need to handle the case of a string not being able to be constructed from the word bank.
I have created two arrays with values in them.
String[] array1 = {"ab", "bc", "ca"};
String[] array2 = {"zy", "yx", "xz"};
I would like to create a third array that obtains specific values from the two arrays.
{"ab", "ca", "yx"}
Instead of simply merging two arrays, is there a way that I can pluck specific values from other arrays when creating the third array?
In Java
You would need to define an interface by which you decide which item is specific and which is not.
public interface SpecificItemDetect{
boolean isSpecific(String item);
}
Now, you can use this code to create your third array.
List<String> third = new ArrayList<String>();
for (String item : Array1){
if(detector.isSpecific(item)){
third.add(item);
}
}
for (String item : Array2){
if(detector.isSpecific(item)){
third.add(item);
}
}
// Now, you may want to convert the list to array.
String[] thirdArray = new String[third.size()];
third.toArray(thirdArray);
Note: detector in this example is an implementation of a class which implements the interface SpecificItemDetect.
In JavaScript
In JavaScript you would need a function instead of that interface. Something like this:
var filter = function(item){
if(/* item is specific */){
return true;
} else {
return false;
}
}
And create the third array like this:
var third = [];
for (var i = 0, len = Array1.length; i < len; i += 1){
if(filter(Array1[i])){
third.push(item);
}
}
for (var i = 0, len = Array2.length; i < len; i += 1){
if(filter(Array2[i])){
third.push(item);
}
}
You cannot access the memory where the array values are stored. This means, you need to go through the array name. Now, with array name you can refer to a specific value you want to 'pluck'. Do you have any rules for this??
Well, I'm not entirely sure what you mean when you say specific values, but if you mean the values that you showed only then you can do it this way
String[] array1 = {"ab", "bc", "ca"};
String[] array2 = {"zy", "yx", "xz"};
List<String> list1 = new ArrayList<String>();
String[] array3 = new String[list1.size()]; //Skip if you don't need array
list1.add(array1[0]);
list1.add(array1[2]);
list1.add(array2[1]);
list1.toArray(array3); //Skip if you don't need array
Much like what abforce said, but if you simply wanted to know how to use the .add method, that is all you need to do. But if you would like to change the values inside when the "specific values" you need change then the interface will be much better. This code is simiple but not very flexible if you need to change the values in the future.
I wrote a function for my cache to retrieve a specific object. This way I don't need to cast it .
#SuppressWarnings("unchecked")
public static <T> T inCache(Class<T> obj, String token) {
Object cacheObj = Cache.get(token);
if (cacheObj != null) {
if (obj.isAssignableFrom(cacheObj.getClass())) {
return (T) cacheObj;
}
}
return null;
}
I am using it like this
String s = inCache(String.class, title);
But now I have a list of Strings in my cache and I can't use it like this
List<String> ipList = Util.inCache(List<String>.class, title);
The problem is the List<String>.class . I am very new to java, how do I have to write it?
There is a concept in java called type erasure. Due to legacy reasons, something like List is just a list. It doesn't remember that it is a list of string at run time. You should just write List.class.
You can then specify the type of object in the List when iterating through it.
You can't get class of List<String>, in your case the only way is:
List<String> ipList = (List<String>)Util.inCache(List.class, title);
You can try :
List<String> ipList = Util.inCache(List.class, title);
Try this-
List<String> inList = (List<String>)Test.inCache(List.class, title);
And you can do also -
List<String> inList = Test.inCache((Class<? extends List<String>>)List.class, token);
Just to clarify Joe's answer ( I don't have enough reputation to comment), at runtime there is no difference between a List <String> and List<Integer> or any other type of List, generics aren't kept at runtime.
Meaning, List<String>.class is completely identical to List<Integer>.class and is actually List.class. This is a weakness of the Java type system. I'm not familiar with a simple way to implement what you wish for.
A code proof for the heck of it :
// It is true that
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
System.out.println( stringList.getClass() == integerList.getClass() );
// And that ...
List objectList = new ArrayList();
System.out.println( stringList.getClass() == objectList.getClass() );
//However, the following is false because a different implementation is used ( I wanted a false case)
List objectLinkedList = new LinkedList();
System.out.println( objectLinkedList.getClass() == objectList.getClass() );
I am brand new to Java :)
I have 2 String lists and I was wondering what would be the most efficient way to compare the two and have a resulting array which contains strings that are not in the other. For example, I have a list called oldStrings and one called Strings. I have seen the Comparator function but don't fully understand how it works, right now I was thinking I could create a for loop, loop through each string and then save that string:
for (final String str : oldStrings) {
if(!strings.contains(str))
{
getLogger().info(str + " is not in strings list ");
}
}
There's going to be up to 200 strings in this list. Would this be the best way to go about this? Thank you!
Collection firstList = new ArrayList() {{
add("str1");
add("str2");
}};
Collection secondList = new ArrayList() {{
add("str1");
add("str3");
add("str4");
}};
System.out.println("First List: " + firstList);
System.out.println("Second List: " + secondList);
// Here is main part
secondList.removeAll(firstList);
System.out.println("Result: " + secondList);
Update:
More sophisticated version of code
Collection<String> firstList = new ArrayList<String>();
firstList.add("str1");
firstList.add("str2");
Collection<String> secondList = new ArrayList<String>();
secondList.add("str1");
secondList.add("str2");
secondList.add("str3");
System.out.println("First List: " + firstList);
System.out.println("Second List: " + secondList);
// Here is main part
secondList.removeAll(firstList);
Update:
To Get acctual difference between both String list go for this.
Set<String> setOne = new HashSet<String>();
Set<String> setTwo = new HashSet<String>();
setOne.add("1");
setOne.add("2");
setOne.add("5");
setTwo.add("1");
setTwo.add("3");
setTwo.add("4");
Set<String> setTwoDummy = new HashSet<String>(setTwo);
setTwo.retainAll(setOne);
setTwoDummy.addAll(setOne);
setTwoDummy.removeAll(setTwo);
System.out.println(""+setTwoDummy);
First, the problem with your solution is that it will only find elements that are in oldStrings and not strings. If you're going with this approach then you need to loop on the other list as well.
If this is not for homework then check out CollectionUtils.disjunction from Apache Commons Collections.
Compare two lists of strings and have a
resulting array which contains strings
that are not in the other.
The description is ambiguous because we don't we don't know if we need just non matching strings from the first list, the second list, or both. Below is pseudo code for both.
for (String str : oldStrings)
{
if(strings.contains(str))
{
intersectionList.add(str);
}
}
oldStrings.removeAll(intersectionList);
strings.removeAll(intersectionList);
result = strings.addAll(oldStrings).toArray();
Or
copyStrings = strings.clone();
strings.removeAll(oldStrings);
oldStrings.removeAll(copyStrings);
result = strings.addAll(oldStrings).toArray();
You should be using Google Guava's Sets utilities.
Set<String> s = Sets.newHashSet("a", "b", "c", "d");
Set<String> t = Sets.newHashSet("f", "g", "a", "c");
Sets.SetView<String> difference = Sets.difference(s, t);
System.out.println(difference); // prints [b, d]