uninitialized slot in arraylist of linkedlist - java

int index = hash(value, size);
if (array.get(index) == null) {
array.add(index, new LinkedList<String>());
}
I have an array of LinkedLists: Arraylist<.LinkedList<.String>>, and I want to add a LinkedList in the array index given if one hasn't been initialized in it yet. Problem is, the index hashes to some number, but the index it goes to doesn't exist, since no LinkedList has been initialized in that index yet, but that's why i am doing if(array.get(index) == null) add a LinkedList, but apparently that's an incorrect comparison to do.
I tried .isEmpty(), null, and .equals(null), they don't work.

The ArrayList doesn't auto-grow, you have to grow it yourself:
int index = hash(value, size);
// grow
if (array.size() <= index) {
array.ensureCapacity(index + 1);
while (array.size() <= index)
array.add(null);
}
if (array.get(index) == null) {
array.set(index, new LinkedList<String>());
}
Note my change of array.add(index, ...) to array.set(index, ...) (docs): add will insert (and shift the rest of the array) while set will overwrite the element at the given index.
As long as you control hash you know the upper limits of its return value (let's call this limit) and you should only need to initialise your array once:
// initialise
ArrayList<LinkedList<String>> array = new ArrayList<>();
array.ensureCapacity(limit);
for (int i = 0; i < limit; ++i)
array.add(null);
// ...
// use
int index = hash(value, size); // hash(...) returns values in 0..limit-1
if (array.get(index) == null) {
array.set(index, new LinkedList<String>());
}
As Tamas Rev stated: you don't have to reinvent the wheel, just use a HashMap. As an additional bonus, HashMap will most likely be faster and generally be more memory efficient (the above scheme allocates an array of limit elements while HashMap can deal with any key type of any size).

Related

How can i delte an item from a 2D Array? [duplicate]

Given an array of n Objects, let's say it is an array of strings, and it has the following values:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
What do I have to do to delete/remove all the strings/objects equal to "a" in the array?
[If you want some ready-to-use code, please scroll to my "Edit3" (after the cut). The rest is here for posterity.]
To flesh out Dustman's idea:
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
Edit: I'm now using Arrays.asList instead of Collections.singleton: singleton is limited to one entry, whereas the asList approach allows you to add other strings to filter out later: Arrays.asList("a", "b", "c").
Edit2: The above approach retains the same array (so the array is still the same length); the element after the last is set to null. If you want a new array sized exactly as required, use this instead:
array = list.toArray(new String[0]);
Edit3: If you use this code on a frequent basis in the same class, you may wish to consider adding this to your class:
private static final String[] EMPTY_STRING_ARRAY = new String[0];
Then the function becomes:
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);
This will then stop littering your heap with useless empty string arrays that would otherwise be newed each time your function is called.
cynicalman's suggestion (see comments) will also help with the heap littering, and for fairness I should mention it:
array = list.toArray(new String[list.size()]);
I prefer my approach, because it may be easier to get the explicit size wrong (e.g., calling size() on the wrong list).
An alternative in Java 8:
String[] filteredArray = Arrays.stream(array)
.filter(e -> !e.equals(foo)).toArray(String[]::new);
Make a List out of the array with Arrays.asList(), and call remove() on all the appropriate elements. Then call toArray() on the 'List' to make back into an array again.
Not terribly performant, but if you encapsulate it properly, you can always do something quicker later on.
You can always do:
int i, j;
for (i = j = 0; j < foo.length; ++j)
if (!"a".equals(foo[j])) foo[i++] = foo[j];
foo = Arrays.copyOf(foo, i);
You can use external library:
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
It is in project Apache Commons Lang http://commons.apache.org/lang/
See code below
ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);
If you need to remove multiple elements from array without converting it to List nor creating additional array, you may do it in O(n) not dependent on count of items to remove.
Here, a is initial array, int... r are distinct ordered indices (positions) of elements to remove:
public int removeItems(Object[] a, int... r) {
int shift = 0;
for (int i = 0; i < a.length; i++) {
if (shift < r.length && i == r[shift]) // i-th item needs to be removed
shift++; // increment `shift`
else
a[i - shift] = a[i]; // move i-th item `shift` positions left
}
for (int i = a.length - shift; i < a.length; i++)
a[i] = null; // replace remaining items by nulls
return a.length - shift; // return new "length"
}
Small testing:
String[] a = {"0", "1", "2", "3", "4"};
removeItems(a, 0, 3, 4); // remove 0-th, 3-rd and 4-th items
System.out.println(Arrays.asList(a)); // [1, 2, null, null, null]
In your task, you can first scan array to collect positions of "a", then call removeItems().
There are a lot of answers here--the problem as I see it is that you didn't say WHY you are using an array instead of a collection, so let me suggest a couple reasons and which solutions would apply (Most of the solutions have already been answered in other questions here, so I won't go into too much detail):
reason: You didn't know the collection package existed or didn't trust it
solution: Use a collection.
If you plan on adding/deleting from the middle, use a LinkedList. If you are really worried about size or often index right into the middle of the collection use an ArrayList. Both of these should have delete operations.
reason: You are concerned about size or want control over memory allocation
solution: Use an ArrayList with a specific initial size.
An ArrayList is simply an array that can expand itself, but it doesn't always need to do so. It will be very smart about adding/removing items, but again if you are inserting/removing a LOT from the middle, use a LinkedList.
reason: You have an array coming in and an array going out--so you want to operate on an array
solution: Convert it to an ArrayList, delete the item and convert it back
reason: You think you can write better code if you do it yourself
solution: you can't, use an Array or Linked list.
reason: this is a class assignment and you are not allowed or you do not have access to the collection apis for some reason
assumption: You need the new array to be the correct "size"
solution:
Scan the array for matching items and count them. Create a new array of the correct size (original size - number of matches). use System.arraycopy repeatedly to copy each group of items you wish to retain into your new Array. If this is a class assignment and you can't use System.arraycopy, just copy them one at a time by hand in a loop but don't ever do this in production code because it's much slower. (These solutions are both detailed in other answers)
reason: you need to run bare metal
assumption: you MUST not allocate space unnecessarily or take too long
assumption: You are tracking the size used in the array (length) separately because otherwise you'd have to reallocate your array for deletes/inserts.
An example of why you might want to do this: a single array of primitives (Let's say int values) is taking a significant chunk of your ram--like 50%! An ArrayList would force these into a list of pointers to Integer objects which would use a few times that amount of memory.
solution: Iterate over your array and whenever you find an element to remove (let's call it element n), use System.arraycopy to copy the tail of the array over the "deleted" element (Source and Destination are same array)--it is smart enough to do the copy in the correct direction so the memory doesn't overwrite itself:
System.arraycopy(ary, n+1, ary, n, length-n)
length--;
You'll probably want to be smarter than this if you are deleting more than one element at a time. You would only move the area between one "match" and the next rather than the entire tail and as always, avoid moving any chunk twice.
In this last case, you absolutely must do the work yourself, and using System.arraycopy is really the only way to do it since it's going to choose the best possibly way to move memory for your computer architecture--it should be many times faster than any code you could reasonably write yourself.
Something about the make a list of it then remove then back to an array strikes me as wrong. Haven't tested, but I think the following will perform better. Yes I'm probably unduly pre-optimizing.
boolean [] deleteItem = new boolean[arr.length];
int size=0;
for(int i=0;i<arr.length;i==){
if(arr[i].equals("a")){
deleteItem[i]=true;
}
else{
deleteItem[i]=false;
size++;
}
}
String[] newArr=new String[size];
int index=0;
for(int i=0;i<arr.length;i++){
if(!deleteItem[i]){
newArr[index++]=arr[i];
}
}
I realise this is a very old post, but some of the answers here helped me out, so here's my tuppence' ha'penny's worth!
I struggled getting this to work for quite a while before before twigging that the array that I'm writing back into needed to be resized, unless the changes made to the ArrayList leave the list size unchanged.
If the ArrayList that you're modifying ends up with greater or fewer elements than it started with, the line List.toArray() will cause an exception, so you need something like List.toArray(new String[] {}) or List.toArray(new String[0]) in order to create an array with the new (correct) size.
Sounds obvious now that I know it. Not so obvious to an Android/Java newbie who's getting to grips with new and unfamiliar code constructs and not obvious from some of the earlier posts here, so just wanted to make this point really clear for anybody else scratching their heads for hours like I was!
Initial array
int[] array = {5,6,51,4,3,2};
if you want remove 51 that is index 2, use following
for(int i = 2; i < array.length -1; i++){
array[i] = array[i + 1];
}
EDIT:
The point with the nulls in the array has been cleared. Sorry for my comments.
Original:
Ehm... the line
array = list.toArray(array);
replaces all gaps in the array where the removed element has been with null. This might be dangerous, because the elements are removed, but the length of the array remains the same!
If you want to avoid this, use a new Array as parameter for toArray(). If you don`t want to use removeAll, a Set would be an alternative:
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
Set<String> asSet = new HashSet<String>(Arrays.asList(array));
asSet.remove("a");
array = asSet.toArray(new String[] {});
System.out.println(Arrays.toString(array));
Gives:
[a, bc, dc, a, ef]
[dc, ef, bc]
Where as the current accepted answer from Chris Yester Young outputs:
[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]
with the code
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
System.out.println(Arrays.toString(array));
without any null values left behind.
My little contribution to this problem.
public class DeleteElementFromArray {
public static String foo[] = {"a","cc","a","dd"};
public static String search = "a";
public static void main(String[] args) {
long stop = 0;
long time = 0;
long start = 0;
System.out.println("Searched value in Array is: "+search);
System.out.println("foo length before is: "+foo.length);
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
System.out.println("==============================================================");
start = System.nanoTime();
foo = removeElementfromArray(search, foo);
stop = System.nanoTime();
time = stop - start;
System.out.println("Equal search took in nano seconds = "+time);
System.out.println("==========================================================");
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
}
public static String[] removeElementfromArray( String toSearchfor, String arr[] ){
int i = 0;
int t = 0;
String tmp1[] = new String[arr.length];
for(;i<arr.length;i++){
if(arr[i] == toSearchfor){
i++;
}
tmp1[t] = arr[i];
t++;
}
String tmp2[] = new String[arr.length-t];
System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length);
arr = tmp2; tmp1 = null; tmp2 = null;
return arr;
}
}
It depends on what you mean by "remove"? An array is a fixed size construct - you can't change the number of elements in it. So you can either a) create a new, shorter, array without the elements you don't want or b) assign the entries you don't want to something that indicates their 'empty' status; usually null if you are not working with primitives.
In the first case create a List from the array, remove the elements, and create a new array from the list. If performance is important iterate over the array assigning any elements that shouldn't be removed to a list, and then create a new array from the list. In the second case simply go through and assign null to the array entries.
Arrgh, I can't get the code to show up correctly. Sorry, I got it working. Sorry again, I don't think I read the question properly.
String foo[] = {"a","cc","a","dd"},
remove = "a";
boolean gaps[] = new boolean[foo.length];
int newlength = 0;
for (int c = 0; c<foo.length; c++)
{
if (foo[c].equals(remove))
{
gaps[c] = true;
newlength++;
}
else
gaps[c] = false;
System.out.println(foo[c]);
}
String newString[] = new String[newlength];
System.out.println("");
for (int c1=0, c2=0; c1<foo.length; c1++)
{
if (!gaps[c1])
{
newString[c2] = foo[c1];
System.out.println(newString[c2]);
c2++;
}
}
Will copy all elements except the one with index i:
if(i == 0){
System.arraycopy(edges, 1, copyEdge, 0, edges.length -1 );
}else{
System.arraycopy(edges, 0, copyEdge, 0, i );
System.arraycopy(edges, i+1, copyEdge, i, edges.length - (i+1) );
}
If it doesn't matter the order of the elements. you can swap between the elements foo[x] and foo[0], then call foo.drop(1).
foo.drop(n) removes (n) first elements from the array.
I guess this is the simplest and resource efficient way to do.
PS: indexOf can be implemented in many ways, this is my version.
Integer indexOf(String[] arr, String value){
for(Integer i = 0 ; i < arr.length; i++ )
if(arr[i] == value)
return i; // return the index of the element
return -1 // otherwise -1
}
while (true) {
Integer i;
i = indexOf(foo,"a")
if (i == -1) break;
foo[i] = foo[0]; // preserve foo[0]
foo.drop(1);
}
to remove  only the first  of several equal entries
with a lambda
boolean[] done = {false};
String[] arr = Arrays.stream( foo ).filter( e ->
! (! done[0] && Objects.equals( e, item ) && (done[0] = true) ))
.toArray(String[]::new);
can remove null entries
In an array of Strings like
String name = 'a b c d e a f b d e' // could be like String name = 'aa bb c d e aa f bb d e'
I build the following class
class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
this.name = name
this.parts = this.name.split(" ")
this.tv = this.parts.size()
}
public String cleared(){
int i
int k
int j=0
for(i=0;i<tv;i++){
for(k=0;k<tv;k++){
if(this.parts[k] == this.parts[i] && k!=i){
this.parts[k] = '';
j++
}
}
}
def str = ''
for(i=0;i<tv;i++){
if(this.parts[i]!='')
this.str += this.parts[i].trim()+' '
}
return this.str
}}
return new clearname(name).cleared()
getting this result
a b c d e f
hope this code help anyone
Regards
Assign null to the array locations.

Merging a 2D array of intervals

Below is code that takes a 2D array (a list of intervals) and merges them. Each interval is of size 2, but the list of intervals is of size n, e.g.
intervals = [[1,2], [2,4], [8,10]]
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
LinkedList<int[]> mergedList = new LinkedList<int[]>();
for (int i = 0; i < intervals.length; i++) {
if (mergedList.size() == 0 || mergedList.getLast()[1] < intervals[i][0]) {
mergedList.add(intervals[i]);
} else {
int max = Math.max(mergedList.getLast()[1], intervals[i][1]);
mergedList.getLast()[1] = max;
// mergedList.getLast() = new int[] { mergedList.getLast()[0], max };
}
}
return mergedList.toArray(new int[mergedList.size()][]);
}
In the else statement, I originally tried the commented line but it gave me an unexpected type error. Why am I unable to replace the array within the mergedList BUT I'm able to replace the value within it? And when replacing the value, how do I know it's not just creating a copy and actually modifying the linked list?
this line is the error
mergedList.getLast() = new int[] { mergedList.getLast()[0], max };
i think you wanted to write setLast in order to modify the last member of the list
mergedList.setLast()
You cannot assign a value to a function like you can to a variable!
a = 123 // works
a() = 123 // doesn't work
I'm guessing you want to overwrite the last item on the list. Since a LinkedList has no setLast method, you first have to determine the index of the last element and then overwrite it with set(index, yourReplacingValueHere).Try this:
mergedList.set(mergedList.indexOf(mergedList.getLast()), yourReplacingValueHere)
Maybe that's an acceptable solution.

arraylist to array unique order

So I'm trying to go through an arraylist of objects that all have a certain strength value and depending on their strength value, they go into the bigger 2d array based on that. So if their strength value is 0 then they go in the 0th array of the bigger one and this is what my code looks like so far
private ArrayList<Battleable> arr;
public BattleDeck() {
arr = new ArrayList<Battleable>();
for (Battleable creature: arr){
arr.add(creature);
}
}
public Battleable[][] export2Darray() {
//returns a two-dimensional ragged array where each row
// contains a deep copy of all of the Battleable objects
// in the BattleStack with the corresponding Level value
Battleable[][] retVal = new Battleable[10][];
int k = 0;
for (int i = 0; i<arr.size(); i++){
int levelOfObj = arr.get(i).getLevel();
if(levelOfObj == k) {
//insert it into retVal[0][0]
}
}
}
return retVal;
}
and I was wondering how I would do that? How do i syntax-tically say "get the obj that has strength 0 and put it in position 0 0 of my 2d array
A solution using Java 8 streams:
// group Battleables ArrayList by strength
Map<Integer, List<Battleable>> map =
arr.stream().collect(Collectors.groupingBy(Battleable::getStrength));
The result is a Map containing the Battleables as Lists with their strength as their key.
If you need the result as a jagged 2D array, sort the entries like this:
final Battleable[][] arrays = new Battleable[10][];
map.entrySet().forEach(entry -> {
arrays[entry.getKey()] = entry.getValue().toArray(new Battleable[entry.getValue().size()]);
});
Since arrays are of fixed size in Java, there is no clean way to add items to an array. You can resize the array each time by creating a new array each time, one larger than the last, and copying the data from the old array to the new array, but that would be messy and you would be reinventing a wheel called ArrayList. Modus Tollens has a good answer, but it uses some slightly advanced Java 8 concepts. Here's one way to write it without them:
public Battleable[][] export2Darray() {
Battleable[][] retVal = new Battleable[10][];
// create a map that will hold the items, arranged by level
Map<Integer, List<Battleable>> byLevel = new HashMap<>();
for (int i = 0; i < 10; i++) {
// initialize all levels with empty lists
byLevel.put(i, new ArrayList<>());
}
for (Battleable battleable : arr) {
int level = battleable.getLevel();
// get the list for this level and add to it
byLevel.get(level).add(battleable);
}
// Now we have a map from levels to lists of battleables;
// we need to turn each list into an array in our retVal
for (int level = 0; level < 10; level++) {
// get each list, convert it toArray and assign to slot in retVal
retVal[level] = byLevel.get(level).toArray(new Battleable[0]);
}
return retVal;
}
Here's a solution using ArrayLists, I am creating an ArrayList which will be referenced by strength, then inside of this I have another ArrayListwhich will have all of the Battleable objects of that strength level.
public ArrayList<ArrayList<Battleable>> exportBattleable() {
ArrayList<ArrayList<Battleable>> retVal = new ArrayList<ArrayList<Battleable>>();
for (int i = 0; i < arr.size(); i++){
retVal.get(arr.getLevel()).add(arr.get(i));
}
return retVal;
}
Now if you want to print all Battleable objects of strength = 3, you would do:
ArrayList<Battleable> strength3 = retVal.get(3);
for(Battleable battleable : strength3) {
System.out.println(battleable.toString());
}
This way you don't have to worry about re-sizing your arrays depending on how many Battleable objects you are adding in, same with strength levels, if you decide that instead of using strength levels from 0-9 that you wanted to use 0-20 you already have the ability to scale up or down.

Questions about implementing my own HashMap in Java

I am working on an assignment where I have to implement my own HashMap. In the assignment text it is being described as an Array of Lists, and whenever you want to add an element the place it ends up in the Array is determined by its hashCode. In my case it is positions from a spreadsheet, so I have just taken columnNumber + rowNumber and then converted that to a String and then to an int, as the hashCode, and then I insert it that place in the Array. It is of course inserted in the form of a Node(key, value), where the key is the position of the cell and the value is the value of the cell.
But I must say I do not understand why we need an Array of Lists, because if we then end up with a list with more than one element, will it not increase the look up time quite considerably? So should it not rather be an Array of Nodes?
Also I have found this implementation of a HashMap in Java:
public class HashEntry {
private int key;
private int value;
HashEntry(int key, int value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
}
public class HashMap {
private final static int TABLE_SIZE = 128;
HashEntry[] table;
HashMap() {
table = new HashEntry[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = null;
}
public int get(int key) {
int hash = (key % TABLE_SIZE);
while (table[hash] != null && table[hash].getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == null)
return -1;
else
return table[hash].getValue();
}
public void put(int key, int value) {
int hash = (key % TABLE_SIZE);
while (table[hash] != null && table[hash].getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
table[hash] = new HashEntry(key, value);
}
}
So is it correct that the put method, looks first at the table[hash], and if that is not empty and if what is in there has not got the key, being inputted in the method put, then it moves on to table[(hash + 1) % TABLE_SIZE]. But if it is the same key it simply overwrites the value. So is that correctly understood? And is it because the get and put method use the same method of looking up the place in the Array, that given the same key they would end up at the same place in the Array?
I know these questions might be a bit basic, but I have spend quite some time trying to get this sorted out, why any help would be much appreciated!
Edit
So now I have tried implementing the HashMap myself via a Node class, which just
constructs a node with a key and a corresponding value, it has also got a getHashCode method, where I just concatenate the two values on each other.
I have also constructed a SinglyLinkedList (part of a previous assignment), which I use as the bucket.
And my Hash function is simply hashCode % hashMap.length.
Here is my own implementation, so what do you think of it?
package spreadsheet;
public class HashTableMap {
private SinglyLinkedListMap[] hashArray;
private int size;
public HashTableMap() {
hashArray = new SinglyLinkedListMap[64];
size = 0;
}
public void insert(final Position key, final Expression value) {
Node node = new Node(key, value);
int hashNumber = node.getHashCode() % hashArray.length;
SinglyLinkedListMap bucket = new SinglyLinkedListMap();
bucket.insert(key, value);
if(hashArray[hashNumber] == null) {
hashArray[hashNumber] = bucket;
size++;
}
if(hashArray[hashNumber] != null) {
SinglyLinkedListMap bucket2 = hashArray[hashNumber];
bucket2.insert(key, value);
hashArray[hashNumber] = bucket2;
size++;
}
if (hashArray.length == size) {
SinglyLinkedListMap[] newhashArray = new SinglyLinkedListMap[size * 2];
for (int i = 0; i < size; i++) {
newhashArray[i] = hashArray[i];
}
hashArray = newhashArray;
}
}
public Expression lookUp(final Position key) {
Node node = new Node(key, null);
int hashNumber = node.getHashCode() % hashArray.length;
SinglyLinkedListMap foundBucket = hashArray[hashNumber];
return foundBucket.lookUp(key);
}
}
The look up time should be around O(1), so I would like to know if that is the case? And if not how can I improve it, in that regard?
You have to have some plan to deal with hash collisions, in which two distinct keys fall in the same bucket, the same element of your array.
One of the simplest solutions is to keep a list of entries for each bucket.
If you have a good hashing algorithm, and make sure the number of buckets is bigger than the number of elements, you should end up with most buckets having zero or one items, so the list search should not take long. If the lists are getting too long it is time to rehash with more buckets to spread the data out.
It really depends on how good your hashcode method is. Lets say you tried to make it as bad as possible: You made hashcode return 1 every time. If that were the case, you'd have an array of lists, but only 1 element of the array would have any data in it. That element would just grow to have a huge list in it.
If you did that, you'd have a really inefficient hashmap. But, if your hashcode were a little better, it'd distribute the objects into many different array elements and as a result it'd be much more efficient.
The most ideal case (which often isn't achievable) is to have a hashcode method that returns a unique number no matter what object you put into it. If you could do that, you wouldn't ever need an array of lists. You could just use an array. But since your hashcode isn't "perfect" it's possible for two different objects to have the same hashcode. You need to be able to handle that scenario by putting them in a list at the same array element.
But, if your hashcode method was "pretty good" and rarely had collisions, you rarely would have more than 1 element in the list.
The Lists are often referred to as buckets and are a way of dealing with collisions. When two data elements have the same hash code mod TABLE SIZE they collide, but both must be stored.
A worse kind of collision is two different data point having the same key -- this is disallowed in hash tables and one will overwrite the others. If you just add row to column, then (2,1) and (1,2) will both have a key of 3, which means they cannot be stored in the same hash table. If you concatenated the strings together without a separator then the problem is with (12,1) versus (1, 21) --- both have key "121" With a separator (such as a comma) all the keys will be distinct.
Distinct keys can land in the same buck if there hashcodes are the same mod TABLE_SIZE. Those lists are one way to store the two values in the same bucket.
class SpreadSheetPosition {
int column;
int row;
#Override
public int hashCode() {
return column + row;
}
}
class HashMap {
private Liat[] buckets = new List[N];
public void put(Object key, Object value) {
int keyHashCode = key.hashCode();
int bucketIndex = keyHashCode % N;
...
}
}
Compare having N lists, with having just one list/array. For searching in a list one has to traverse possibly the entire list. By using an array of lists, one at least reduces the single lists. Possibly even getting a list of one or zero elements (null).
If the hashCode() is as unique as possible the chance for an immediate found is high.

Get objects' index in a Java List

I have a list of strings in my (Android) Java program, and I need to get the index of an object in the list. The problem is, I can only find documentation on how to find the first and last index of an object. What if I have 3 or more of the same object in my list? How can I find every index?
Thanks!
You need to do a brute force search:
static <T> List<Integer> indexesOf(List<T> source, T target)
{
final List<Integer> indexes = new ArrayList<Integer>();
for (int i = 0; i < source.size(); i++) {
if (source.get(i).equals(target)) { indexes.add(i); }
}
return indexes;
}
Note that this is not necessarily the most efficient approach. Depending on the context and the types/sizes of lists, you might need to do some serious optimizations. The point is, if you need every index (and know nothing about the structure of the list contents), then you need to do a deathmarch through every item for at best O(n) cost.
Depending on the type of the underlying list, get(i) may be O(1) (ArrayList) or O(n) (LinkedList), so this COULD blow up to a O(n2) implementation. You could copy to an ArrayList, or you could walk the LinkedList incrementing an index counter manually.
If documentation is not helping me in my logic in this situation i would have gone for a raw approach for Traversing the list in a loop and saving the index where i found a match
ArrayList<String> obj = new ArrayList<String>();
obj.add("Test Data"): // fill the list with your data
String dataToFind = "Hello";
ArrayList<Integer> intArray = new ArrayList<Integer>();
for(int i = 0 ; i<obj.size() ; i++)
{
if(obj.get(i).equals(dataToFind)) intArray.add(i);
}
now intArray would have contained all the index of matched element in the list
An alternative brute force approach that will also find all null indexes:
static List<Integer> indexesOf(List<?> list, Object target) {
final List<Integer> indexes = new ArrayList<Integer>();
int offset = 0;
for (int i = list.indexOf(target); i != -1; i = list.indexOf(target)) {
indexes.add(i + offset);
list = list.subList(i + 1, list.size());
offset += i + 1;
}
return indexes;
}

Categories