How to make a Java array behave like a JavaScript array? - java

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

Related

How to sort List<String> list numerically?

I have a List<String> list which is initialized to an arrayList. That is,
List<String>list = new ArrayList();
It has the following elements.
[1,bread, 1,turkey, 10,potato, 11,plum, 12,carrot, 2,milk, 2,rice]
I would like to sort the list so that the numbers are in ascending order. For example,
[1,bread,1 turkey,2,milk,2,rice,10,potato,11,plum,12,carrot]
How can I do that?
Java is an Object-Oriented language, and you should use it.
So, create a new class with two fields: int and String.
Now parse your strings and create objects, i.e. 1,bread is parsed into the int value 1, and the String value bread.
Next, make your class implement Comparable, and implement the compareTo method to order the objects by the int value.
Finally, now that List<String> was converted to List<MyObj>, call Collections.sort(list).
You're not trying to sort the elements in the List--you're trying to sort pairs of elements. You can't do that with a simple sort. What you'll need to do is:
Define a class with two fields, an int and a String. Make the class implement Comparable.
Define a comparator for the class that compares the int fields to get the order you want. You'll have to decide what your comparator will do if the int fields are equal (do you want the String fields to be in ascending order?)
Create a List<YourClass> whose size is half the size of the original list, by going through the source list in pairs, something like
for (int i = 0; i < list.size() - 1; i += 2) {
create a YourClass by converting list.get(i) to an int, and using list.get(i+1) as the String field
}
Sort the new list
If desired, recreate a List<String> by going through the List<YourClass> and adding a String conversion of the int, followed by the String field from YourClass, to the new list.
I don't know what you're planning to do with the String list, but in most cases it will make your program easier if you create a List<YourClass> list as soon as possible, and work with YourClass objects throughout the rest of the program
The simple answer is that you could provide a custom Comparator which understands the structure of each individual String element and can parse and compare them properly. Something like this:
#Test
public void testShouldSortByNumber() {
// Arrange
List<String> list = Arrays.asList("1,bread", "1,turkey", "10,potato", "11,plum", "12,carrot", "2,milk", "2,rice");
final List<String> EXPECTED_LIST = Arrays.asList("1,bread", "1,turkey", "2,milk", "2,rice", "10,potato", "11,plum", "12,carrot");
// Act
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
try {
int i1 = Integer.parseInt(o1.split(",")[0]);
int i2 = Integer.parseInt(o2.split(",")[0]);
// If the numbers are equal, could order by alpha on the second part of the string split
return i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
} catch (Exception e) {
// Lots of possible errors above -- NPE, NFE, invalid string format, etc.
e.printStackTrace();
}
return 0;
}
});
// Assert
assert list.equals(EXPECTED_LIST);
}
The more complex answer is that you should better define your problem -- what should the result be if an element is empty or null, if the numbers are equal are the other strings compared lexicographically or is it irrelevant?
You may also want to use a different data structure -- if the content of each element is really two different logical concepts, a tuple or class may be correct. Or, you may want to use a SortedMap (of which TreeMap is probably the best implementation here) where the key is the "ingredient" and the value is the "count" (or "cost", I don't have any context on the numerical value).
You can also enhance the code above with a lambda if you have access to JDK 8+.

Java Collection, Set, Map or Array to hold unique sorted non blank strings

I am fairly new to java and would like a container that I can use to hold strings that are not empty and have them sorted.
So far, I have mostly been using ArrayList, but this seems a bit limited for this case.
Thanks
Use TreeSet or TreeMap, depending on your requirements. Both are collections that accept unique elements and keep them sorted.
A Set is what you want, as the items in it have to be unique.
As the Strings should be sorted you'll need a TreeSet.
As for the non blank Strings you have to override the insertion methods like this:
Set<String> sortedSetOfStrings = new TreeSet<String>() {
#Override
public boolean add(String s) {
if(s.isEmpty())
return false;
return super.add(s);
}
};
EDIT: Simplified thanks to Peter Rader's comment.
Thanks for all the help. Here is what I eventually came up with, using TreeSet and apache commons StringUtils. My Input is a CSV String so, I didn't use the check on the input.
String csvString = "Cat,Dog, Ball, Hedge,, , Ball, Cat"
String[] array = StringUtils.split((String) csvString, ",");
for (int i = 0; i < array.length; i++)
{
array[i] = array[i].trim(); //Remove unwanted whitespace
}
set = new TreeSet<String>(Arrays.asList(array));
set.remove(""); //Remove the one empty string if it is there
set now contains: Ball,Cat,Dog,Hedge

Adding value to java array in the right place

I am trying to write a little program that will contain a array of profiles of people and I am stuck on the method for adding the profiles, as I would like them to be added in correct place so it doesn't need to be sorted. For example
If I have a array with 3 profiles
Potter, H
Smith, T
Warren, B
And I want to add Summer, P I would like it to be added right between the 1st and 2nd index
Before anyone asks I haven't got much code for this as I am still thinking on how to search the array and say where the profile needs to be placed.
Any ideas are appreciated
(Also it needs to be a Array not a ArrayList or any other data structure)
If you want to use an array rather than a decent, appropriate data structure, then use Arrays.binarySearch() to find the appropriate location. But you'll have to shift all the subsequent elements.
Whatever you are talking about is best done by the LinkedList http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html
Since you want to use Array only, then as you know arrays have a constant number of elements that you declare. So I recommend you to create a temporary ArrayList and then copy those elements into an array that you want. Here how it's done
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
String[] yourInitialArray = { "Potter, H", "Smith, T", "Warren, B" };
// Creating a temporary ArrayList
ArrayList<String> temporary = new ArrayList<String>();
for (int i = 0; i < yourInitialArray.length; i++) {
if (i != 1) {
temporary.add(yourInitialArray[i]);
} else {
temporary.add("Summer, P");
temporary.add(yourInitialArray[i]);
}
}
yourInitialArray = new String[temporary.size()];
for (int j = 0; j < temporary.size(); j++) {
yourInitialArray[j] = temporary.get(j);
System.out.println(yourInitialArray[j]);
}
}
}
try to adding normally after that sort the list.It is better to use
First of all, I would highly recommend using the Collections framework List over the Arrays. because it provides the lot of flexibility and improvements over using normal arrays
and for your solution, i would recommend using the LinkedList. This provides the method add(int index, E element ) for inserting the element at specific location and it is very efficient

How to search an array for a part of string?

I have an arraylist<string> of words. I sort it using Collections.sort(wordsList);
I'm using this array for an auto-suggest drop down box, so that when the user is typing in a letter, they are given a list of suggestions similar to what they are typing in.
How do I go about searching this array for a prefix of string, say the user types in "mount" and the array contains the word "mountain", how can I search this array and return similar values.
Here's my code so far:
public List<Interface> returnSuggestedList(String prefix) {
String tempPrefix = prefix;
suggestedPhrases.clear();
//suggestedPhrases = new ArrayList<Interface>();
//Vector<String> list = new Vector<String>();
//List<Interface> interfaceList = new ArrayList<Interface>();
Collections.sort(wordsList);
System.out.println("Sorted Vector contains : " + wordsList);
int i = 0;
while (i != wordsList.size()) {
int index = Collections.binarySearch(wordsList, prefix);
String tempArrayString = wordsList.get(index).toString();
if (tempArrayString.toLowerCase().startsWith(prefix.toLowerCase())) {
ItemInterface itemInt = new Item(tempArrayString);
suggestedPhrases.add(itemInt);
System.out.println(suggestedPhrases.get(i).toString());
System.out.println("Element found at : " + index);
}
i++;
}
return suggestedPhrases;
}
The most basic approach would be
List<String> result = new ArrayList<String>();
for(String str: words){
if(str.contains(keyword){
result.add(str);
}
}
You can improve this version, if you only concern with startWith instead of contains then you can distribute words in a HashMap and you will have narrowed search
For this task, there are better data structures than a sorted array of strings. You might look e.g. at DAWG (Directed acyclic word graph).
If wordList is fixed (does not change from one method call to the other) you should sort it somewhere else, because sort is costly, and store it in lowercase.
In the rest of the method you would do something like:
List<String> selected = new ArrayList<String>();
for(String w:wordList){
if(w.startsWith(prefix.toLower())) // or .contains(), depending on
selected.add(w); // what you want exactly
}
return selected;
Also see the trie data structure. This question has useful info. I should think its getPrefixedBy() will be more efficient than anything you can roll by hand quickly.
Of course, this will work for prefix searches only. Contains search is a different beast altogether.
As #Jiri says you can use a DAWG, but if you don't want to go that far you can do some simple and useful things.
Make use of the sorting
If you want to sort the array of words do it previously. don't sort it each time
As it's sorted you can find the first and the last word in the list that are matches. The use list.subList(from, to) to return sublist. It's a little more optimal that adding each one.
Use a pre-sorted structure
Use a TreeSet<String> for storing the strings (the will be sorted internally).
Then use treeSet.subSet(from, true, to, false);
Where from is the prefix and to is the "prefix plus one char". By example if you're looking for abc, to must be abd. If you don't want to make that char transformation anyway you can ask for treeSet.headSet(from) and iterate over it until there are no more prefixes.
This is specially useful if you read more than you write. Maybe ordering strings is a little expensive but once ordered you can find them very fast (O(log n)).
Case insensitive comparing
You can provide a Comparator<String> to the tree set in order to indicate how it must order the strings. You cam implement it or maybe there are a prebuild case-insensitive comparator over there.
Anyway its code should be:
int compare(String a, String b) {
return a.toLowerCase().compareTo(b.toLowerCase());
}
Here is a similar example:
-> http://samuelsjoberg.com/archive/2009/10/autocompletion-in-swing

How to lowercase every element of a collection efficiently?

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));

Categories

Resources