Capture duplicates from array without using any inbuilt functions - java

I have been given a task to write my own implementation for removing duplicate objects from an array. The array is unsorted.
As an example, I have this array of objects
ItemsList[] objects = {
new ItemsList("ob1"),
new ItemsList("ob2"),
new ItemsList("ob2"),
new ItemsList("ob1"),
new ItemsList("ob3")
};
"ob1" stands for itemId
My goal is to get the result array like this ["ob1", "ob2", "ob3"], but given NullPointerException when trying to find objects that aren't doubled and add those to array.
Note: cannot use Set, HashSet, ArrayList, Arrays.copyOf, Sort etc. or any other tools such as iterators.
So far I've done this:
public String[] removeDuplicates(ItemsList[] objects) {
String[] noDubs = new String[objects.length];
int len = objects.length;
int pos = 0;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
if (objects[i].getItemId().equals(objects[j].getItemId())) {
noDubs[pos] = objects[i].getItemId();
pos++;
}
else {
//NullPointerException given
if (!objects[i].getItemId().equals(objects[j].getItemId()) && !objects[i].getItemId().contains(noDubs[i])) {
noDubs[pos] = objects[i].getItemId();
pos++;
}
}
}
}
String[] result = new String[pos];
for(int k = 0; k < pos; k++) {
result[k] = noDubs[k];
}
return result;
}
getItemId is class ItemsList method

Here is another option. This copies entries to a buffer the first time it finds them, and then copies the buffer to a correctly sized array.
There is an advantage to looking for duplicates in the buffer, instead of the original array. If there are a lot of duplicates, then there will be fewer checks when looking in the buffer compared to when looking in the original array.
I pulled out the loop to check if an item is in the buffer into another function. This avoids nesting the for loops, which can make it easier to read.
I think this overall approach also reduces the number of variables required to keep track, which also helps make it easier to read.
private static ItemsList[] removeDuplicates(ItemsList[] arr) {
ItemsList[] buffer = new ItemsList[arr.length];
int bufferLength = 0;
for (ItemsList candidate : arr) {
if (!isInBuffer(candidate, buffer, bufferLength)) {
buffer[bufferLength] = candidate;
bufferLength++;
}
}
ItemsList[] result = new ItemsList[bufferLength];
for (int i = 0; i < bufferLength; i++) {
result[i] = buffer[i];
}
return result;
}
private static boolean isInBuffer(ItemsList candidate, ItemsList[] buffer, int bufferLength) {
for(int i = 0; i < bufferLength; i++) {
if (Objects.equals(candidate, buffer[i])) {
return true;
}
}
return false;
}

Here is an implementation. Just mark the item as duplicated if it is equal to one of the next elements. Later add it to the output array, which will need to grow.
public String[] removeDuplicates(ItemList[] items) {
String[] output = {};
for (int i = 0; i < items.length; i++) {
boolean isDuplicated = false;
ItemList current = items[i];
if (current == null)
throw new RuntimeException("item can not be null");
for (int j = i + 1; j < items.length; j++) {
if (current.equals(items[j])) {
isDuplicated = true;
break;
}
}
if (!isDuplicated) {
String[] temp = new String[output.length + 1];
System.arraycopy(output, 0, temp, 0, output.length);
temp[output.length] = current.getItemId();
output = temp;
}
}
return output;
}
You could also make every duplicate null and later add each non null element to the output array, like this:
public String[] removeDuplicates2(ItemList[] items) {
String[] temp = new String[items.length];
int inTemp = 0;
for (ItemList item : items) {
boolean isDuplicated = false;
if (item == null)
throw new RuntimeException("item can not be null");
for (int i = 0; i < inTemp; i++) {
if (item.getItemId().equals(temp[i])) {
isDuplicated = true;
break;
}
}
if (!isDuplicated) temp[inTemp++] = item.getItemId();
}
String[] output = new String[inTemp];
System.arraycopy(temp, 0, output, 0, inTemp);
return output;
}
But note that the first solution is faster

It would be better to use an intermediate array of booleans to track the duplicates and define the length of the result array. This would facilitate detection of multiple duplicates when the same element might occur more than 2 times.
Also, we need to make sure the method equals (and possibly hashCode) is properly overridden in ItemList:
// class ItemList
public boolean equals(Object o) {
if (null == o || !(o instanceof ItemList)) {
return false;
}
if (o == this) return true;
ItemList that = (ItemList) o;
return Objects.equals(this.itemId, that.itemId);
}
public int hashCode() {
return Objects.hash(this.itemId);
}
When checking for equality of ItemList it may be better to use Objects.equals to handle null values without throwing a NullPointerException. Thus, duplicate null entries in the input items will be filtered out too.
public static String[] removeDuplicates(ItemList[] items) {
final int n = items.length;
if (n < 1) {
return new String[0];
}
boolean[] dups = new boolean[n];
int dupCount = 0;
for (int i = 0; i < n; i++) {
ItemList current = items[i];
for (int j = i + 1; j < n; j++) {
if (dups[j]) {
continue;
}
if (Objects.equals(current, items[j])) {
dups[j] = true;
dupCount++;
}
}
}
String[] output = new String[n - dupCount];
for (int i = 0, j = 0; i < n; i++) {
if (!dups[i]) {
output[j++] = null == items[i] ? "<NULL>" : items[i].getItemId();
}
}
// info message
System.out.printf("Found and removed %d duplicate value%s%n", dupCount, dupCount != 1 ? "s" : "");
return output;
}
Test:
ItemList[] items = {
null, new ItemList("ob1"), new ItemList("ob2"), new ItemList("ob2"), new ItemList("ob1"),
new ItemList("ob3"), null, new ItemList("ob3"), new ItemList(null), new ItemList("ob5"),
new ItemList("ob2"), new ItemList(null), new ItemList("ob4"), new ItemList("ob5"), null,
};
System.out.println(Arrays.toString(removeDuplicates(items)));
// compare removal of duplicates to using set
System.out.println("\nUsing Set");
Set<ItemList> set = new LinkedHashSet<>(Arrays.asList(items));
System.out.println(set);
Output:
Found and removed 8 duplicate values
[<NULL>, ob1, ob2, ob3, null, ob5, ob4]
Using Set
[null, {id=ob1}, {id=ob2}, {id=ob3}, {id=null}, {id=ob5}, {id=ob4}]

Related

How can I eliminate/remove a duplication of an object array element which is duplicated a ton of time in the array. (Return same array type)

I tried this for loop but when for duplicated element in the array the inner loop breaks and if more than 10 repeated element are place in the array then the outer-loop brakes.
I need to return an array of same object type since I need to use the methods to pick some values from it.
public Mode insT(Guide[] guide){
Guide[] guideVo = checkGuideDuplication(guide);
}
public Guide[] checkGuideDuplication (Guide[] guide){
for(int i = 0; i<guide.length-1; i++){
for(int j = i+1; i<guide.length; i++){
if(guide[i].getGuide().trim().equals(guide[j].getGuide().trim())){
guide = (Guide[]) ArrayUtils.remove(guide);
}
}
}
return guide;
}
You need to reset the inner index once you remove an element so it gets checked (and bounds-checked) again:
guide = (Guide[]) ArrayUtils.remove(guide);
j--;
You can avoid the inner loop entirely if you use a map to weed out duplicates:
public Guide[] checkGuideDuplication (Guide[] guide){
Map<String, Guide> uniques = new HashMap<>();
for(Guide g : guide){
uniques.putIfAbsent(g.getGuide().trim(), g);
}
return uniques.values().toArray(new Guide[0]);
}
The most performing O(N) solution would be to use Map as shown in shmosel's answer.
But if using Map is not an option due to some constraints/limitations (e.g. only arrays are allowed), another solution would be to set removed elements to null and count the number of deletions, then shift nulls to the end of the array and return a truncated array:
public Guide[] checkGuideDuplication (Guide ... guide) {
int deleted = 0;
for (int i = 0; i < guide.length-1; i++) {
if (null == guide[i]) {
continue;
}
String currGuide = guide[i].getGuide().trim();
for(int j = i + 1; j < guide.length; j++) {
if (null == guide[j]) {
continue;
}
if (currGuide.equals(guide[j].getGuide().trim())) {
guide[j] = null;
deleted++;
}
}
}
// shift remaining elements
for (int i = 0, j = 0; i < guide.length; i++) {
if (guide[i] != null) {
guide[j++] = guide[i];
}
}
return Arrays.copyOf(guide, guide.length - deleted);
}

Array required but Integer found

I am trying to compare two values present in two different arrays but I end up getting the " Array required but Integer found " compile time error . I am really not able solve this. I have marked the line from where the error was coming. It would be very appreciable if anybody can help me out with this. Here is the code .
public class Banker
{
int proccess, n, allocated[][], need[][], maximum[][], available[], safe[];
boolean done[];
public Banker(int n, int proccess) {
this.n = n;
this.proccess = proccess;
allocated = new int[n][n];
need = new int[n][n];
maximum = new int[n][n];
safe = new int[proccess];
done = new boolean[proccess];
}
public void getSafeSequence() {
int result = 0;
for (int i = 0; i < proccess; ++i) {
result = getLocation();
if (result != -1) {
safe[i] = result;
done[result] = true;
} else {
System.out.println(" No Safe Sequence Exist ");
break;
}
}
if (result != -1)
DisplaySequene();
}
public int getLocation() {
boolean flag = true;
for (int i = 0; i < proccess; ++i) {
if (done[i] != true) {
flag = true;
for (int j = 0; j < n; ++j)
***if (available[i][j] < need[i][j])*** {
flag = false;
break;
}
}
if (flag)
return i;
}
return -1;
}
}
available is one dimensional array so you cannot write available[i][j]. Change it to smh like available[i]
You defined available[] as a one dimensional array and use it with two dimensions available[i][j].

Java Array Error

New to java programming and I am currently trying to create a class similar to ArrayList using Arrays.
Am trying to add elements to an array and expand the array by copying them to a new array of bigger size.
I am getting an out of index error at 20.
Code may be messy but currently really stuck.
public class MyArrayList{
private String[] strings;
private int arraySize;
private int storedStrings;
public MyArrayList(int arraySize){
this.arraySize = arraySize;
this.strings = new String[arraySize];
}
public void addString(String string){
storedStrings = 0;
for (int i = 0; i < this.arraySize;i ++){
if (strings[i] != null){
storedStrings = storedStrings +1;
}
}
if (storedStrings == this.arraySize){
String[] newArray = new String[this.arraySize+10];
for (int i = 0; i < this.strings.length; i++){
strings[i] = newArray[i];
}
this.strings = newArray;
newArray[storedStrings] = string;
this.arraySize = this.arraySize +10;
}
else{
strings[storedStrings] = string;
}
for(int i = 0; i < strings.length; i++)
{
//System.out.println(strings[i]);
}
}
}
The code is being run in the test class where the error is being generated on line 10 of test class and line 47 of MyArrayList class.
This is the test code
public class TestArrayList{
public static void main(String[] args)
{
MyArrayList a = new MyArrayList(10);
for (int i = 0; i <50; i++){
a.addString("Test" + i);
}
for (int i = 0; i<50;i++){
System.out.println(a.getString(i*5));
}
}
}
you can do it like this:
public void addString(String string){
if (storedStrings == this.arraySize){
this.arraySize += 10;
String[] newArray = new String[this.arraySize];
for (int i = 0; i < this.storedStrings; i++){
newArray[i] = strings[i];
}
this.strings = newArray;
}
if (strings[storedStrings] == null){
strings[storedStrings++] = string;
}
// remove this loop it will show repeating values otherwise
for(int i = 0; i < storedStrings; i++)
{
System.out.println(strings[i]);
}
}
edit: as you are new to java always think about how can you do more with less code, how to avoid repetition of code, how to merge things that do common task. That will help you write better code
edit2 : the problem is with this loop
for (int i = 0; i<50;i++){
System.out.println(a.getString(i*5));
}
if you have 50 elements in array the getString method on (eg) i = 25 will be 25*5 = 125 which is not the index in the array that's why you are getting ArrayIndexOutOfBound Exception.
you can add
public int size(){
return storedStrings;
}
to check the size of your list which is the maximum item that is inside the list
First with your code there is a mistake in this line
strings[i] = newArray[i];
because you arenĀ“t copying the old data to new array but cleaning the strings array, I suppose that you wish do the contrary action.
In other hand you have extra code that you could improve.
public class MyArrayList{
private String[] strings;
private int arraySize;
public MyArrayList(int arraySize){
this.arraySize = arraySize;
this.strings = new String[arraySize];
}
public void addString(String string){
// Since you always do this
// it's better to use a local variale
int storedStrings = 0;
// Use the foreach syntax
// it's less prone to errors
// and easier to read
for (String s : this.strings){
if (s != null){
storedStrings++;
}else{
// since you want to count the strings in your array
// and you put them in this array
// one after the other
// no need to check the whole array
// when you find null you can exit the loop
break;
}
}
if (storedStrings == this.arraySize){
String[] newArray = new String[this.arraySize+10];
for (int i = 0; i < this.strings.length; i++){
// here we need to copy the content of strings in newArray
// NOT the other way
newArray[i] = this.strings[i];
}
this.strings = newArray;
newArray[storedStrings] = string;
this.arraySize += 10;
}else{
this.strings[storedStrings] = string;
}
}
public String[] getStrings(){
return this.strings;
}
}
As for the test class
public static void main(String[] args){
MyArrayList a = new MyArrayList(10);
for (int i = 0; i <50; i++){
a.addString("Test" + i);
}
for (String s : a.getStrings()){
System.out.println(a);
}
}

How do you copy the components of an ArrayList to a regular Array?

public boolean makeReservation(int id, AvilaNatalyPassenger request) {
boolean status = true;
ArrayList<Integer> inputValues = new ArrayList<Integer>();
for (int i = 0; i < 22; i++) {
for (int j = 0; j < 5; j++) {
id = seats[i][j];
if (id != -1) {
if (inputValues.contains(id)) {
status = false;
break;
}
else {
inputValues.add(id);
for(int a = 0; a < inputValues.size; a++)
seats[a] = inputValues[a];
}
}
}
}
return status;
}
This is what I have but its not correct. I need to add what I have in inputVaule arrayList into the array seats.
You can also look at the Java API: http://docs.oracle.com/javase/7/docs/api/index.html?java/util/ArrayList.html
public Object[] toArray()
Returns an array containing all of the elements in this list in proper sequence (from first to last element).
So this is what you could do:
seats[a] = inputValues.toArray();
Furthermore you cannot use inputValues[a] since it is not an array. What you probably could do is
seats[a] = (inputValues.toArray())[a];
To answer your question, here is an example:
ArrayList<String> stock_list = new ArrayList<String>();
stock_list.add("stock1");
stock_list.add("stock2");
String[] stockArr = new String[stock_list.size()];
stockArr = stock_list.toArray(stockArr);
for(String s : stockArr)
System.out.println(s);
Example is taken from here

Removing unfilled values or null values from array of String in Java [duplicate]

This question already has answers here:
How to efficiently remove all null elements from a ArrayList or String Array?
(18 answers)
Closed 7 months ago.
I have following String Array
tmp = [null, null, null, Mars, Saturn, Mars] coming after doing the operation -
allSig[d3].split(" "); where allSig is an array of Strings. The null value is empty value in the array. Now I want to remove the null. For this I am using
tmp[indexNumber] != null is not working and giving true ; taking null as the value. Even if i am using "null" as a string is not working.
How to remove this.
public static String[] removeElements(String[] allElements) {
String[] _localAllElements = new String[allElements.length];
for (int i = 0; i < allElements.length; i++)
if (allElements[i] != null)
_localAllElements[i] = allElements[i];
return _localAllElements;
}
public static String[] clean(final String[] v) {
int r, w;
final int n = r = w = v.length;
while (r > 0) {
final String s = v[--r];
if (!s.equals("null")) {
v[--w] = s;
}
}
return Arrays.copyOfRange(v, w, n);
}
or
public static String[] clean(final String[] v) {
int r, w, n = r = w = v.length;
while (r > 0) {
final String s = v[--r];
if (!s.equals("null")) {
v[--w] = s;
}
}
final String[] c = new String[n -= w];
System.arraycopy(v, w, c, 0, n);
return c;
}
Works fine...
public static void main(final String[] argv) {
final String[] source = new String[] { "Mars", "null", "Saturn", "null", "Mars" };
assert Arrays.equals(clean(source), new String[] { "Mars", "Saturn", "Mars" });
}
You're creating an array with same size as the original one. So it's the same as the original array, as you copy non null values and default values are null.
Do this :
public static String[] removeElements(String[] allElements) {
// 1 : count
int n = 0;
for (int i = 0; i < allElements.length; i++)
if (allElements[i] != null) n++;
// 2 : allocate new array
String[] _localAllElements = new String[n];
// 3 : copy not null elements
int j = 0;
for (int i = 0; i < allElements.length; i++)
if (allElements[i] != null)
_localAllElements[j++] = allElements[i];
return _localAllElements;
}
Abstracting #az answer, this applies to any class type:
#SuppressWarnings("unchecked")
public static <T> T[] clean(T[] a) {
List<T> list = new ArrayList<T>(Arrays.asList(a));
list.removeAll(Collections.singleton(null));
return list.toArray((T[]) Array.newInstance(a.getClass().getComponentType(), list.size()));
}
If you want the array to contain only the non-null values (i.e. the resulting array would be ["Mars", "Saturn", "Mars"]), then I would look at this as a two part problem.
First, you must identify what the size of the new array should be. From inspection, it's easy to see that it's 3, but you will need to need to count them to calculate this programmatically. You can do this by saying:
// Calculate the size for the new array.
int newSize = 0;
for (int i = 0; i < allElements.length; i++) {
if (allElements[i] != null) {
newSize++;
}
}
Secondly, you will need to create a new array with that size. Then you can put all of the non-null elements into your new array, as you have done above.
// Populate the new array.
String[] _localAllElements = new String[newSize];
int newIndex = 0;
for (int i = 0; i < allElements.length; i++) {
if (allElements[i] != null) {
_localAllElements[newIndex] = allElements[i];
newIndex++;
}
}
// Return the new array.
return _localAllElements;
You can just combine these two components as the new content of your results method. See the full combined code and live sample output here.
public static String[] removeElements(String[] allElements) {
String[] _localAllElements = new String[allElements.length];
int j = 0;
for (int i = 0; i < allElements.length; i++)
if ( allElements[i] != null && !allElements[i].equals(""))
_localAllElements[j++] = allElements[i];
return _localAllElements;
}
This is a very old question but this Java 8+ solution might be useful to someone:
public static String[] removeElements(String[] allElements) {
return Arrays.stream(allElements)
.filter(Objects::nonNull)
.collect(Collectors.toArray());
}
or if you, like me, are a fan of readable code and don't want static methods to get in your way, you can simplify this even further using static imports:
public static String[] removeElements(String[] allElements) {
return stream(allElements).filter(Objects::nonNull).collect(toArray());
}

Categories