I'm looking for a simple way to apply a callback method to each element in a String array. For instance in PHP I can make all elements in an array like this:
$array = array_map('strtolower', $array);
Is there a simple way to accomplish this in Java?
First, object arrays in Java are vastly inferior to Lists, so you should really use them instead if possible. You can create a view of a String[] as a List<String> using Arrays.asList.
Second, Java doesn't have lambda expressions or method references yet, so there's no pretty way to do this... and referencing a method by its name as a String is highly error prone and not a good idea.
That said, Guava provides some basic functional elements that will allow you to do what you want:
public static final Function<String, String> TO_LOWER =
new Function<String, String>() {
public String apply(String input) {
return input.toLowerCase();
}
};
// returns a view of the input list with each string in all lower case
public static List<String> toLower(List<String> strings) {
// transform in Guava is the functional "map" operation
return Lists.transform(strings, TO_LOWER);
}
Unlike creating a new array or List and copying the lowercase version of every String into it, this does not iterate the elements of the original List when created and requires very little memory.
With Java 8, lambda expressions and method references should finally be added to Java along with extension methods for higher-order functions like map, making this far easier (something like this):
List<String> lowerCaseStrings = strings.map(String#toLowerCase);
There's no one-liner using built-in functionality, but you can certainly match functionality by iterating over your array:
String[] arr = new String[...];
...
for(int i = 0; i < arr.length; i++){
arr[i] = arr[i].toLowerCase();
}
You could use reflection:
String[] map(java.lang.reflect.Method method, String[] array) {
String[] new_array = new String[array.length];
for (int i = 0; i < array.length; i++) new_array[i] = (String)method.invoke(null, new Object[]{array[i]});
return new_array;
}
Then you just need to declare a static method somewhere and get a reference to it using the reflection API.
Related
I have built a static method that adds an element to an array (which has a fixed size). You don't have to look at the entire method, it just creates a new array with a greater length and adds an element at the end of it, then returns the new array.
static int[] add(int[] oldArray, int value){
int n = oldArray.length;
int[] newArray = new int[n+1];
for(int i=0; i<n; i++){
newArray[i]=oldArray[i];
}
newArray[n] = value;
return newArray;
}
The method is supposed to be used as follows
int[] a = {2, 5};
a = add(a, 7);
Now the array a has three elements instead of two, namely 2, 5 and 7. The problem is, this is still a little messy. Is there a way to implement the method as non-static (in a "predefined array class" or something? I'm not too sure how to express it better) in such a way that it would work as follows instead?
int[] a = {2, 5};
a.add(7);
I'm trying to achieve this without using ArrayLists and NestedLists.
You cannot add a method to "the array class", same for all predefined classes, the only solution for other predefined classes is to inherit them and add the methods you want, but, this cannot be done for arrays as it has not a specific predefined class, it can be defined as a container object that holds a fixed number of values of a single type (Arrays).
The alternative solutions for what you want:
Use Lists (ArrayList for example), as described in the comments.
concatenate the array original content with the new element, for this solution, you can use ArrayUtils.addAll(T[] array1, T... array2) or System.arraycopy like the following sample (convert the new element to an array before)
String[] both = ArrayUtils.addAll(first, second);
Create a class to wrap the array (adding the array as a variable in this class), and create addElement method containing something like the following:
int[] newArray = new int[length + 1];
for (int i = 0; i < length; i++)
newArray[i] = this.array[i];
newArray[length] = element;
length ++;
array = newArray;
Is there a way to implement the method as non-static (in a "predefined array class" or something? I'm not too sure how to express it better) in such a way that it would work as follows instead?
No, there is not. You must use something like List, or optionally write your own interface that wraps an array (it cannot itself be an array).
What you're asking for are called "extension methods" in C#, but as others have already answered, they don't exist in Java. However, Project Lombok (which is full of very useful features that most professional Java developers should be aware of and use), implements them with a simple annotation.
Here's an example:
package so_75073262;
public class ArrayExtensions {
public static int[] add(int[] oldArray, int value) {
int n = oldArray.length;
int[] newArray = new int[n + 1];
for (int i = 0; i < n; i++) {
newArray[i] = oldArray[i];
}
newArray[n] = value;
return newArray;
}
}
package so_75073262;
import lombok.experimental.ExtensionMethod;
#ExtensionMethod(ArrayExtensions.class)
public class Usage {
public static void main(String[] args) {
int[] original = {2,5};
int[] modified = original.add(7);
System.out.println(modified[0]);
System.out.println(modified[1]);
System.out.println(modified[2]);
}
}
Lombok is a form of "magic" and probably would get "interesting" responses from some course instructors; I'm not sure I'd recommend using this in an introductory Java class. But it's still useful to know about; it's a powerful tool to have in your toolbox, and can help keep code tidy and uncluttered.
I think you should take a reference of How ArrayList is getting implemented and how its size increases dynamically. Since it uses Array internally for the implementation, you might get some suggestions from there.
In JavaScript, I can write code like this:
var a = new Array();
a[2] = 'a';
a[20] = 'b';
and this would not work on Java, the point is I don't want to specific the exact length for it.
How could I keep this happy style when writing java?
If you don't want to specific length you can use List like this:
List<Character> list = new ArrayList<>();
list.add('a');
list.add('b');
You cannot. Java is to Javascript as ham is to hamster. There is no reason to believe they have the same syntax.
If you want a sparse array, use a Map:
final Map<Integer, Character> a = new LinkedHashMap<>();
a.put(2, 'a');
a.put(20, 'b');
When you want an array of characters you can do it like this:
char[] array = new char[30];
array[2] = 'a';
array[20] = 'b';
Java and JavaScript are two deferent languages. you can't do same thing in both
In Java you can write
char[] arr=new char[2];
arr[0]='a';
arr[1]='b';
If you don't want to specific the length, you can use List in Java
List<Character> list=new ArrayList<>();
list.add('a');
list.add('b');
As others already pointed out: Java and JavaScript are two different things. For containers with variable size there is the Java collections framework.
But wich to choose? That depends on what you need. From your question I can imagine two cases:
a variable sized, indexed container:
basically an array-like list. In Java there's besides other list implementations the ArrayList used as follows:
List<Character> myList = new ArrayList<Character>();
// insert element at the end of the list
myList.add('a');
// insert element at specific position in list
myList.add(1, 'b');
// this will fail, because there's no element at position 2!!!
myList.add(3, 'c')
a container for mappings from integer to character:
In java there's lots of map implementations, I propose the HashMap, used like this:
Map<Integer,Character> myMap = new HashMap<Integer,Character>();
// insert mappings int -> char
myMap.put(0, 'a');
myMap.put(1, 'b');
myMap.put(20, 'c');
Each Container serves a different purpose. I advise reading the Java collections tutorial to be able to choose the best fitting one. Also take a look at tucuxi's answer, as he presented a solution wich simulates the desired beahviour but consider that (as he said himself) this is not the java way of doing things!
You can always write your own. You will not get the syntax, but most of the flavor will still be there.
Note that, efficiency-wise, this is a terrible idea. You can write much better code by learning "the Java way" of doing things. This is true of all languages: programming against the grain of the language is sure to cause you pain.
But here is the code:
class MyArray<T> extends ArrayList<T> {
public MyArray<T>() { super(); }
public void add(int i, T value) {
if (size() < i) {
ensureCapacity(i+1); // grow at most once instead of multiple times
while (size() < i)) {
add(null); // extend with a null object
}
add(value);
} else {
add(i, value);
}
}
}
Now you can compare a garden-variety ArrayList with an instance of MyArray:
ArrayList<Character> a = new ArrayList<>();
MyArray<Character> b = new MyArray<>()
a.add(10, 'X'); // IndexOutOfBoundsException, size is 0
b.add(10, 'X'); // no exception - you get [10 x null, 'X']
b.get(10); // returns 'X'
Bear in mind that JavaScript arrays can be indexed by arbitrary objects and not only integers -- but that the JavaScript VM tries to use numerically-indexed arrays if at all possible. For arbitrary indexing, you would need to use a Java HashMap:
class MyArray2<T> extends HashMap<Object, T> {
public MyArray2<T>() { super(); }
public void add(Object o, T value) { set(o, value); }
}
You would then use as:
MyArray2<Character> c = new MyArray2<>()
c.add("anything", '?');
c.get("anything"); // returns '?'
It depends, if you are going to use an array of a fixed size you can use:
char myarray[]=new char[50];
myarray[2]='a';
myarray[20]='b';
If you are going to change the size of the array dynamically you can use a Collection like an ArrayList (look at the doc) and insert chars in the positions you want
like this
char arr[]=new char[30]; //declares an array which can hold 30 characters
arr[2]='a';
arr[20]='b';
but if you don't want to specify the length,than arraylist is something which will help you to accomplish your task because array's size is always fixed in Java
I am trying to Learn Java as I am a beginner and recently i fumbled upon Vectors and Lists in Java. This is a very simple and a basic question, but any help would be really helpful for a learner.
I have created a vector v as shown below:
public vector createVector(){
Vector v = new Vector();
v.add(Path1); //Path1 is the path of a directory
v.add(Path2);
return v;
}
I have a function in which I pass, one of the parameter is v.get(i). The function is shown below:
for(int i=0,i<v.size(),i++){
qlm("Write", "init",getList(),**v.get(i)**); // Function call.
}
Function declaration is :
Void qlm(String Option, String init, List lists, **String paths**){
}
I am not able to match the parameter in the function call which is v.get(i) with String Paths. Please share your knowledge.
Thanks a lot.
Without Generics, v.get(i) will always return an object. Here are two ways to resolve it:
Declare Vector as
Vector< String > v = new Vector< String > ();
Or do
v.get(i).toString();
But before doing v.get(i).toString(), null check should be performed on v.get(i).
try this
for(int i=0,i<v.size(),i++){
qlm("Write", "init",getList(),v.get(i).toString()); // Function call.
}
Typically, in Java, when somebody declares a Vector they will declare it using Generics. To declare a Vector that will contain strings, you would write this:
Vector<String> myVector = new Vector<String>();
Then, to get a iterate over it's values, you would do this:
for(int i = 0; i < myVector.size(); i++){
String s = myVector.get(i); // The get() method here returns a String instead of Object
}
Or, because Vectors are enumerable, you could do this:
for(String s : myVector){
// There is now a variable named s available in the loop that
// will contain each element in the vector in turn.
}
That being said, you really shouldn't use Vectors any more. They are pretty old, and there are better lists available in Java. I would recommend that you use an ArrayList, but they're a variety of lists available which can be found here under "All known implementing classes."
To rewrite your example using generics and an ArrayList, you would do this:
List<String> myList = new ArrayList<String>();
myList.add(Path1);
myList.add(Path2);
for(String s : myList){
qlm("Write", "init", getList(), s);
}
I'd like to use the following class like so:
for(String device : new Devices())
{
//
}
If I provide direct access to the internal string array, then there is no problem:
for(String device : new Devices().getAllDevices()) //getAllDevices would be a String[]
{
//
}
But I just want to forward the iterator, which would be simple if AllDevices were an ArrayList.
public final class Devices implements Iterable<String>{
private static final String MyKindleFire = "123156448975312";
private static final String[] AllDevices = new String[]{MyKindleFire};
#Override
public Iterator<String> iterator() {
// if AllDevices were an array list, this would be possible
// but how should I do this for an array?
return AllDevices.iterator();
}
}
This works, but I'd like to know a better way if possible:
#Override
public Iterator<String> iterator() {
return Arrays.asList(AllDevices).iterator();
}
Unfortunately, you cannot do it without converting your array to List<T>: iterating over arrays with the "foreach" version of the for loop is a "compiler trick", i.e. something the compiler knows and does internally.
An ability to use primitives in "foreach" loops is an indirect indication that Iterator<T> is not used there, because Java generics cannot be used with primitive types.
String[] someArray = ....;
List<String> someList = java.util.Arrays.asList(someArray);
someList.iterator();
I think this is the only way to get an Iterator of an array in pure java.
If you are using apache commons-collections you can simply use:
org.apache.commons.collections.IteratorUtils.arrayIterator(Object[])
See http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections/IteratorUtils.html
You could use Guava's Iterators.forArray(T...) to make an iterator.
Alternatively, make an Iterable out of your array (e.g. with Arrays.asList(T...)) and return its .iterator().
What's the most efficient way to lower case every element of a List or Set?
My idea for a List:
final List<String> strings = new ArrayList<String>();
strings.add("HELLO");
strings.add("WORLD");
for(int i=0,l=strings.size();i<l;++i)
{
strings.add(strings.remove(0).toLowerCase());
}
Is there a better, faster way? How would this example look like for a Set? As there is currently no method for applying an operation to each element of a Set (or List) can it be done without creating an additional temporary Set?
Something like this would be nice:
Set<String> strings = new HashSet<String>();
strings.apply(
function (element)
{ this.replace(element, element.toLowerCase();) }
);
Thanks,
Yet another solution, but with Java 8 and above:
List<String> result = strings.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
This seems like a fairly clean solution for lists. It should allow for the particular List implementation being used to provide an implementation that is optimal for both the traversal of the list--in linear time--and the replacing of the string--in constant time.
public static void replace(List<String> strings)
{
ListIterator<String> iterator = strings.listIterator();
while (iterator.hasNext())
{
iterator.set(iterator.next().toLowerCase());
}
}
This is the best that I can come up with for sets. As others have said, the operation cannot be performed in-place in the set for a number of reasons. The lower-case string may need to be placed in a different location in the set than the string it is replacing. Moreover, the lower-case string may not be added to the set at all if it is identical to another lower-case string that has already been added (e.g., "HELLO" and "Hello" will both yield "hello", which will only be added to the set once).
public static void replace(Set<String> strings)
{
String[] stringsArray = strings.toArray(new String[0]);
for (int i=0; i<stringsArray.length; ++i)
{
stringsArray[i] = stringsArray[i].toLowerCase();
}
strings.clear();
strings.addAll(Arrays.asList(stringsArray));
}
You can do this with Google Collections:
Collection<String> lowerCaseStrings = Collections2.transform(strings,
new Function<String, String>() {
public String apply(String str) {
return str.toLowerCase();
}
}
);
If you are fine with changing the input list here is one more way to achieve it.
strings.replaceAll(String::toLowerCase)
Well, there is no real elegant solution due to two facts:
Strings in Java are immutable
Java gives you no real nice map(f, list) function as you have in functional languages.
Asymptotically speaking, you can't get a better run time than your current method. You will have to create a new string using toLowerCase() and you will need to iterate by yourself over the list and generate each new lower-case string, replacing it with the existing one.
Try CollectionUtils#transform in Commons Collections for an in-place solution, or Collections2#transform in Guava if you need a live view.
This is probably faster:
for(int i=0,l=strings.size();i<l;++i)
{
strings.set(i, strings.get(i).toLowerCase());
}
I don't believe it is possible to do the manipulation in place (without creating another Collection) if you change strings to be a Set. This is because you can only iterate over the Set using an iterator or a for each loop, and cannot insert new objects whilst doing so (it throws an exception)
Referring to the ListIterator method in the accepted (Matthew T. Staebler's) solution. How is using the ListIterator better than the method here?
public static Set<String> replace(List<String> strings) {
Set<String> set = new HashSet<>();
for (String s: strings)
set.add(s.toLowerCase());
return set;
}
I was looking for similar stuff, but was stuck because my ArrayList object was not declared as GENERIC and it was available as raw List type object from somewhere. I was just getting an ArrayList object "_products". So, what I did is mentioned below and it worked for me perfectly ::
List<String> dbProducts = _products;
for(int i = 0; i<dbProducts.size(); i++) {
dbProducts.add(dbProducts.get(i).toLowerCase());
}
That is, I first took my available _products and made a GENERIC list object (As I were getting only strings in same) then I applied the toLowerCase() method on list elements which was not working previously because of non-generic ArrayList object.
And the method toLowerCase() we are using here is of String class.
String java.lang.String.toLowerCase()
not of ArrayList or Object class.
Please correct if m wrong. Newbie in JAVA seeks guidance. :)
Using JAVA 8 parallel stream it becomes faster
List<String> output= new ArrayList<>();
List<String> input= new ArrayList<>();
input.add("A");
input.add("B");
input.add("C");
input.add("D");
input.stream().parallel().map((item) -> item.toLowerCase())
.collect(Collectors.toCollection(() -> output));