I used a HashMap to store the occurrences of each element, and then iterated over the hash map to get duplicated element, but something doesn't feel right about this solution.
Problem statement in Firecode.io:
Write a method duplicate to find the repeated or duplicate elements in an array. This method should return a list of repeated integers in a string with the elements sorted in ascending order (as illustrated below).
duplicate({1,3,4,2,1}) --> "[1]"
duplicate({1,3,4,2,1,2,4}) --> "[1, 2, 4]"
Note: You may use toString() method to return the standard string representation of most data structures, and Arrays.sort() to sort your result.*
Here is my code:
public String duplicate(int[] numbers) {
HashMap < Integer, Integer > hs = new HashMap < Integer, Integer > ();
for (int i = 0; i < numbers.length; i++) {
if (hs.get(numbers[i]) == null) {
hs.put(numbers[i], 1);
} else hs.put(numbers[i], (Integer) hs.get(numbers[i]) + 1);
}
int size = 0;
for (int i: hs.keySet()) {
if (hs.get(i) > 1) {
size++;
}
}
int j = 0;
int[] a = new int[size];
for (int i: hs.keySet()) {
if (hs.get(i) > 1) {
a[j++] = i;
}
}
Arrays.sort(a);
return Arrays.toString(a);
}
Here's the way I would do it: (comments for educational purposes, would probably not have them in production code.)
public String duplicate(int[] numbers) {
// holds the items we've encountered more than once.
// TreeSet<> keeps things in sorted order for us.
final SortedSet<Integer> duplicates = new TreeSet<>();
// keeps track of items we've encountered.
final Set<Integer> encountered = new HashSet<>();
// iterate over every number
for (final int number : numbers) {
// Add the item to encountered. Set.add() will return true if
// the element is new to the set.
if (!encountered.add(number)) {
// Since the element wasn't new, ensure this item exists in the duplicates collection.
duplicates.add(number);
}
}
return duplicates.toString();
}
Since you don't have to tell how many times an element is duplicated you only need a Set to remember which elements are unique and which not. If you know the element values (e.g. numbers between 1 and 10) you could further simplify Set to boolean[] or a bit vector:
int[] numbers = {1, 3, 4, 2, 2, 1, 2, 4, 4};
Set<Integer> unique = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int n : numbers) {
if (!unique.add(n)) {
duplicates.add(n);
}
}
List<Integer> result = new ArrayList<>(duplicates);
result.sort(Integer::compareTo);
System.out.println(result); // [1, 2, 4]
If you are using Java 8 or beyond you can try:
public String duplicate(int[] numbers) {
Map<Integer, Integer> hs = new HashMap<>();
for ( int i : numbers ) {
hs.merge( i, 1, Integer::sum);
}
return '[' +
hs.entrySet()
.stream()
.filter( e -> e.getValue() > 1 )
.map(Entry::getKey)
.sorted()
.map(i -> i.toString())
.collect(Collectors.joining(", ")) +
']';
}
Related
Does Java or Guava have something that will return most common element in a list?
List<BigDecimal> listOfNumbers= new ArrayList<BigDecimal>();
[1,3,4,3,4,3,2,3,3,3,3,3]
return 3
In statistics, this is called the "mode". A vanilla Java 8 solution looks like this:
Stream.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.ifPresent(System.out::println);
Which yields:
3=8
jOOλ is a library that supports mode() on streams. The following program:
System.out.println(
Seq.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
.mode()
);
Yields:
Optional[3]
For simplicity's sake, I omitted using BigDecimal. The solution would be the same, though.
(disclaimer: I work for the company behind jOOλ)
This is fairly easy to implement yourself:
public static <T> T mostCommon(List<T> list) {
Map<T, Integer> map = new HashMap<>();
for (T t : list) {
Integer val = map.get(t);
map.put(t, val == null ? 1 : val + 1);
}
Entry<T, Integer> max = null;
for (Entry<T, Integer> e : map.entrySet()) {
if (max == null || e.getValue() > max.getValue())
max = e;
}
return max.getKey();
}
List<Integer> list = Arrays.asList(1,3,4,3,4,3,2,3,3,3,3,3);
System.out.println(mostCommon(list));
3
If you want to handle cases where there's more then one most frequent element, you can scan the list once to determine how many times the most frequent element(s) occur, and then scan the list again, put those elements in a set and return that.
Probably the simplest solution with Guava looks like
Multiset<BigDecimal> multiset = HashMultiset.create(listOfNumbers);
BigDecimal maxElement = null;
int maxCount = 0;
for (Multiset.Entry<BigDecimal> entry : multiset.entrySet()) {
if (entry.getCount() > maxCount) {
maxElement = entry.getElement();
maxCount = entry.getCount();
}
}
That's a complete solution, and shorter than the other alternatives I see discussed.
Here is a pure Java 8 solution (note: do not use this one, see below):
List<Integer> theList = Arrays.asList(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3);
Integer maxOccurredElement = theList.stream()
.reduce(BinaryOperator.maxBy((o1, o2) -> Collections.frequency(theList, o1) -
Collections.frequency(theList, o2))).orElse(null);
System.out.println(maxOccurredElement);
Another solution, by collecting the elements to a map by their frequency, then finding the entry with max value and returning its key (basically the same solution on arshajii's answer, written using Java 8):
Integer maxVal = theList.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream().max((o1, o2) -> o1.getValue().compareTo(o2.getValue()))
.map(Map.Entry::getKey).orElse(null);
Update: If the most frequent elements are more than one, and you want to get all of them in a collection, I propose two methods:
Method A: After collecting the original collection to a map with keys as elements and values as their number of occurrences, getting the entry with the maximum value and filtering the map entries with value equal to this max value (if) we found. Something like this:
Map<Integer, Long> elementCountMap = theList.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<Integer> result = elementCountMap.values().stream()
.max(Long::compareTo).map(maxValue -> elementCountMap.entrySet().stream()
.filter(entry -> maxValue.equals(entry.getValue())).map(Map.Entry::getKey).collect(Collectors.toList()))
.orElse(Collections.emptyList());
Method B: After collecting the original collection to a map with keys as elements and values as their number of occurrences, transforming this map into a new map with keys as number of occurences, values as a list of elements with this number of occurences. And then finding the max element of this map with a custom comparator which compares the keys, and getting the value of this entry. Like this:
List<Integer> result = theList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
.entrySet().stream().max((o1, o2) -> o1.getKey().compareTo(o2.getKey())).map(Map.Entry::getValue)
.orElse(Collections.emptyList());
Guava provides a method that will help, though it's less efficient than Louis's solution.
BigDecimal mostCommon =
Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(listOfNumbers))
.iterator().next();
The classic way to do this is to sort the list and then work through them one by one:
public static BigInteger findMostCommon(List<BigInteger> list) {
Collections.sort(list);
BigInteger mostCommon = null;
BigInteger last = null;
int mostCount = 0;
int lastCount = 0;
for (BigInteger x : list) {
if (x.equals(last)) {
lastCount++;
} else if (lastCount > mostCount) {
mostCount = lastCount;
mostCommon = last;
}
last = x;
}
return mostCommon;
}
This is a bit more space efficient than using a hash to tally counts since it sorts the array in place. You could toss this into a generics class and replace BigInteger with T, or just use Object in place of BigInteger.
Here is an extension of Louis' answer that support the case where there is multiple elements with same max occurrence count:
private <T> List<T> getMostFrequentElements(List<T> list) {
Multiset<T> multiset = HashMultiset.create(list);
List<T> mostFrequents = new ArrayList<>();
int maxCount = 0;
for (Multiset.Entry<T> entry : multiset.entrySet()) {
if (entry.getCount() > maxCount) {
maxCount = entry.getCount();
mostFrequents.clear();
mostFrequents.add(entry.getElement());
} else if (entry.getCount() == maxCount) {
mostFrequents.add(entry.getElement());
}
}
return mostFrequents;
}
We can do in only one iteration with ease:
public static Integer mostFrequent(List<Integer> list) {
if (list == null || list.isEmpty())
return null;
Map<Integer, Integer> counterMap = new HashMap<Integer, Integer>();
Integer maxValue = 0;
Integer mostFrequentValue = null;
for(Integer valueAsKey : list) {
Integer counter = counterMap.get(valueAsKey);
counterMap.put(valueAsKey, counter == null ? 1 : counter + 1);
counter = counterMap.get(valueAsKey);
if (counter > maxValue) {
maxValue = counter;
mostFrequentValue = valueAsKey;
}
}
return mostFrequentValue;
}
Find most frequent item in collection:
private <V> V findMostFrequentItem(final Collection<V> items)
{
return items.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Functions.identity(), Collectors.counting())).entrySet().stream()
.max(Comparator.comparing(Entry::getValue))
.map(Entry::getKey)
.orElse(null);
}
If you are willing to use Google Guava, you can use its MultiSet classes:
MultiSet<BigNumber> numbers = HashMultiSet.create();
numberSet.addAll(list);
Set<MultiSet.Entry<BigNumber>> pairs = numbers.emtrySet();
Set<MultiSet.Entry<BigNumber>> copies = new HashSet<MultiSet.Entry<BigNumber>>(pairs);
Now, sort copies by its values descending.
I’m learning Java 8 streams. Tell me pls, how can I write a sortArray method more compactly?
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertArrayEquals;
public class TestStream {
/*
* Sort numbers in an array without changing even numbers position
*/
#Test
public void test_1() {
int[] nonSorted = new int[]{3, 4, 5, 2, 1, 6, 9, 8, 7, 0};
int[] expected = new int[]{1, 4, 3, 2, 5, 6, 7, 8, 9, 0};
Integer[] arr = sortArray(nonSorted);
int[] sorted = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
sorted[i] = arr[i];
}
assertArrayEquals(expected, sorted);
}
private Integer[] sortArray(int[] array) {
Map<Integer, Integer> even = extractEven(array);
Integer[] withoutEvens = removeEven(array);
int length = even.size() + withoutEvens.length;
Integer[] result = new Integer[length];
Arrays.sort(withoutEvens);
for (int i = 0; i < withoutEvens.length; i++) {
result[i] = withoutEvens[i];
}
even.forEach((k, v) -> {
System.arraycopy(result, k, result, k + 1, length - k - 1);
result[k] = v;
});
return result;
}
private Map<Integer, Integer> extractEven(int[] array) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < array.length; i++) {
if (array[i] % 2 == 0) {
map.put(i, array[i]);
}
}
return map;
}
private Integer[] removeEven(int[] array) {
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < array.length; i++) {
if (array[i] % 2 != 0) {
list.add(array[i]);
}
}
Integer[] a = new Integer[list.size()];
return list.toArray(a);
}
}
One can think of a solution like:
First we extract the odd integers from the nonSorted[] and put them on a stack in sorted fashion.
Why we should use the stack in a sorted fashion??
The final array
needs to be sorted on odd Integers basis, the stack follows FIFO(First in Last
Out) policy.
Now we take an Instream and run it from 0 to nonSorted.length-1 and check the original nonSorted for the odd Integer; as soon as we find one we replace it with the first element of the stack and pop() the element from the stack.
Note: One needs to play around the stack as not every time you will
need sorted elements in the stack, but in OP's case this happens to
be.
int[] nonSorted = new int[]{3, 4, 5, 2, 1, 6, 9, 8, 7, 0};
LinkedList<Integer> stack = Arrays.stream(nonSorted)
.sorted().filter(s -> s % 2 != 0).boxed()
.collect(Collectors.toCollection(LinkedList::new));
int[] expected = IntStream.rangeClosed(0, nonSorted.length - 1)
.map(s -> nonSorted[s] % 2 != 0 ? stack.pop():nonSorted[s])
.toArray();
I really liked the idea of using a sorted Stack, but it is not easily parallelizable and got me curious how to solve that.
My idea is sorting indices of uneven elements and depending on the position of the index we can distinguish during the creation of the result array if a number is even or not.
public int[] sortUnevenElements(int[] nonSorted) {
int[] unevenIndices = IntStream.range(0, nonSorted.length).filter(i -> nonSorted[i] % 2 != 0).toArray();
int[] sortedUnevenIndices = Arrays.stream(unevenIndices, 0, unevenIndices.length).boxed()
.sorted(Comparator.comparingInt(i -> nonSorted[i])).mapToInt(Integer::intValue).toArray();
return IntStream.range(0, nonSorted.length).map(i -> {
int idx = Arrays.binarySearch(unevenIndices, i);
return idx >= 0 ? nonSorted[sortedUnevenIndices[idx]] : nonSorted[i];
}).toArray();
}
I believe what you mean by Java-8 is using Streams and other APIs introduced since that release. You already have a very well-performing code in my opinion though. The way I could think of breaking down the problem is as follows -
Find the odd and even numbers and their mappings to the current indexes. Such that even values with their indexes would remain fixed.
Upon the odd numbers and their indexes, remap the values sorting them naturally.
Once all of this is done, merge these split odd-even maps based upon the indexes.
Retrieve the values from this merged result.
Overall implementation of this would look something like -
private Integer[] sortArrayStream(Integer[] array) {
Map<Boolean, Map<Integer, Integer>> evenOdds = IntStream.range(0, array.length)
.boxed()
.collect(Collectors.partitioningBy(i -> array[i] % 2 == 0,
Collectors.toMap(o -> o, i -> array[i]))); //1
Map<Integer, Integer> oddSorted = remapWithSorting(evenOdds.get(Boolean.FALSE)); // 2
Map<Integer, Integer> overall = new HashMap<>(evenOdds.get(Boolean.TRUE));
overall.putAll(oddSorted); // part of 3
return overall.entrySet().stream()
.sorted(Map.Entry.comparingByKey()) // remaining of 3
.map(Map.Entry::getValue) // 4
.toArray(Integer[]::new);
}
private Map<Integer, Integer> remapWithSorting(Map<Integer, Integer> initialIndexMapping) {
List<Integer> oddIndexes = new ArrayList<>(initialIndexMapping.keySet());
List<Integer> sortedOdds = initialIndexMapping.values().stream()
.sorted().collect(Collectors.toList());
return IntStream.range(0, sortedOdds.size())
.boxed()
.collect(Collectors.toMap(oddIndexes::get, sortedOdds::get));
}
This is an insertion sort trial with streams. The nonSorted array is streamed and collected to a new int[]. If the value from nonSorted array is even it is just copied, otherwise if it is odd an insertion sort is run just for odd values already present in the result.
int[] sort = IntStream.range(0, nonSorted.length)
.collect(() -> new int[nonSorted.length], (ints, i) -> {
ints[i] = nonSorted[i];
if (nonSorted[i] % 2 != 0) {
AtomicInteger current = new AtomicInteger(i);
IntStream.iterate(i - 1,
(v) -> current.get() > 0 && v >= 0,
(v) -> --v)
.forEach(ind -> {
if (ints[ind] % 2 != 0) {
if (ints[ind] > nonSorted[i]) {
ints[current.get()] = ints[ind];
ints[ind] = nonSorted[i];
current.set(ind);
} else {
current.set(-1);
}
}
});
}
}, (a1, a2) -> {
});
I am almost at end of code. I am supposed to find number of times numbers appeared in a given array. The for loop is not working as expected.
They contain numbers in an array, I am able to extract individual numbers which are repeating. Then I am trying to find how many time that an individual number is appeared by using for loop and store it into another array which will give me the count.
Everything is declared like d[], b[], c[]
for (i = 0; i < k; i++) {
for (j = 0; j < l; j++) {
if (d[i] == c[j]) {
b[i]++;
}
}
}
Expected output should be, like if if's condition to be true, b[i] should increment the number of times a number appeared but it is giving me array of ones, like it is only passing through the if condition once per i.
You can do that using for example a Hashtable saving the array numbers as keys and the number of repetitions as value. This function receive an array of Integers, and returns the Hashtable with the repetitions:
public static Hashtable<Integer, Integer> getRepitedNumbers( Integer[] numbers) {
Hashtable<Integer, Integer> Result = new Hashtable<Integer, Integer>();
for( int i = 0; i < numbers.length; i++) {
if( Result.containsKey( numbers[ i])) {
//If the current number is saved in the hashtable, you need to increment the
//value (repetitions counter for this number)
Result.put( numbers[ i], Result.get( numbers[ i]) + 1);
} else {
//If the current number doesn't exist, is the first occurrence.
Result.put( numbers[ i], 1);
}
}
//At the end you have a hashtable with each number and the number of occurrences
return Result;
}
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
public static void main(String[] args) {
List<Integer> listOfIntegers = Arrays.asList(1, 2, 3, 1, 2, 3, 3, 3, 3, 8, 9);
Map<Integer, Long> integerToCount = listOfIntegers.stream().collect(Collectors.groupingBy(it -> it, Collectors.counting()));
System.out.println(integerToCount);
}
What about using Streams:
public static Map<Integer, Long> countItems(Integer[] arr) {
return Arrays.stream(arr).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}
I know how to find the highest value and index in a array(list). But I dont know how to get the indexes if there are multiple highest values in a array. I want to create a method/function that can two things: fill the array(list) with only one index if there is only one highest value, or create a arraylist if there are multiple highest values. For example I give two array's:
Array1={42,3,42,42,42,5,8};
I want to get the all the indexes of value 42 in a new array(list).
Array2={42,3,35,67};
I want to create a array(list) with only one index of value 42.
Try this for multiple indexes
List<Integer> list = new ArrayList<>();
int array[] = {1,1,2,4,5,3,1,5};
int max = array[0];
list.add(0);
for(int i=1;i<array.length;i++){
if(max<array[i]){
max = array[i];
list.clear();
list.add(i);
}else if(max==array[i])
list.add(i);
}
System.out.println(list);
For single index, use an extra variable, to store it it.
Using Java 8 features and assuming the array is not empty:
int maxValue = Arrays.stream(array)
.max()
.getAsInt();
int[] maxIndexes = IntStream.range(0, array.length)
.filter(i -> array[i] == maxValue)
.toArray();
That's 2 iterations where first you find the max value and then the indexes where an array element is equal to the max value.
Some documentation if you are not familiar with some classes/methods above:
IntStream, toArray(), getAsInt()
Depending on your scenario, having a small data set or a large data set, you might want to process the items sequentially or in parallel.
NOTE: the following code contains JUnit #Test annotation and AssertJ assertions.
Solution: sequential, one pass, small data set
This solution parses the array and keeps track of maximum and current maximum indexes. If a new maximum is found the indexes are cleared and the new maximum indexes are inserted.
#Test
public void sequential_algorithm_return_max_with_indexes() {
int[] values = new int[]{42, 3, 42, 42, 42, 5, 8};
int maxValue = Integer.MIN_VALUE;
List<Integer> maxValueIndexes = new ArrayList<>();
for (int index = 0; index < values.length; index++) {
int value = values[index];
if (value == maxValue) {
maxValueIndexes.add(index);
} else {
if (value > maxValue) {
maxValue = value;
maxValueIndexes.clear();
maxValueIndexes.add(index);
}
}
}
assertThat(maxValue).isEqualTo(42);
assertThat(maxValueIndexes).containsExactly(0, 2, 3, 4);
}
Solution: parallel, large data set
Streams are flexible and allow parallel processing.
Bellow data is represented as a pair of index-value instead of an array. This is done in order to transform the array of pairs into a stream and keep track of indexes.
Because this supposed to work in parallel, reduce method accepts 3 arguments - initial value, accumulator and combiner. This means that multiple buckets run in parallel. For each bucket there is an initial value and an accumulator used to process items sequentially. Then the parallel results of buckets are combined using the combiner argument.
#Test
public void parallel_algorithm_return_max_with_indexes() {
Pair<Integer, Integer>[] values = new Pair[]{
new Pair<>(0, 42),
new Pair<>(1, 3),
new Pair<>(2, 42),
new Pair<>(3, 42),
new Pair<>(4, 42),
new Pair<>(5, 5),
new Pair<>(6, 8),
};
ValueIndexes<Integer> maxValueIndexes = Arrays.stream(values)
.parallel()
.reduce(
new ValueIndexes<>(Integer.MIN_VALUE),
(ValueIndexes<Integer> valueIndexes, Pair<Integer, Integer> value) -> {
if (valueIndexes.getValue() == value.getValue()) {
valueIndexes.addIndex(value.getKey());
} else {
if (value.getValue() > valueIndexes.getValue()) {
valueIndexes = new ValueIndexes<>(value.getValue());
valueIndexes.addIndex(value.getKey());
}
}
return valueIndexes;
},
(valueIndexes1, valueIndexes2) -> {
if (valueIndexes1.getValue() == valueIndexes2.getValue()) {
ValueIndexes<Integer> valueIndexes = new ValueIndexes<>(valueIndexes1.getValue());
valueIndexes.addIndexes(valueIndexes1.getIndexes());
valueIndexes.addIndexes(valueIndexes2.getIndexes());
return valueIndexes;
} else {
if (valueIndexes1.getValue() > valueIndexes2.getValue()) {
return valueIndexes1;
} else {
return valueIndexes2;
}
}
}
);
assertThat(maxValueIndexes.getValue()).isEqualTo(42);
assertThat(maxValueIndexes.getIndexes()).containsExactlyInAnyOrder(0, 2, 3, 4);
}
private class ValueIndexes<T> {
private T value;
private List<Integer> indexes = new ArrayList<>();
public ValueIndexes(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public Iterable<Integer> getIndexes() {
return indexes;
}
public void addIndexes(Iterable<Integer> indexes) {
indexes.forEach(this::addIndex);
}
public void addIndex(int index) {
indexes.add(index);
}
}
I'm trying to count how many duplicate items are in an array.
Example:
[0, 2, 0] would return 2, [0, 0, 0] would return 3, [0, 1, 2] = 0
So far I have it working for when all three items are equal, but I'm not sure why it's returning one less than what it should for 2 items being the same.
int equal = 0;
for(int i = 0; i < recent.length; i++) {
for(int j = i; j < recent.length; j++) {
if(i != j && recent[i].equals(recent[j])) {
equal++;
}
}
}
Your algorithm is flawed in the following way: for every element in the array you look at all the elements after that element and if they happen to be equal, you increase the counter. However when you have 3 same elements, you count the last one twice - when you run internal loop for first and for second element. Moreover you never count the first element.
So it works by accident for [0, 0, 0] but doesn't work for other inputs.
I think that having nested loops is quite inefficient. You should be able to do it in o(n) rather than o(n^2).
If you time yours against the following...
public void run() {
int[] array = createRandomArray(2000000, 1000000);
System.out.println(countNumDups1(array));
}
private int[] createRandomArray(int numElements, int maxNumExclusive) {
int[] array = new int[numElements];
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(maxNumExclusive);
}
return array;
}
private int countNumDups1(int[] array) {
Map<Integer, Integer> numToCountMap = new HashMap<>();
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.containsKey(key)) {
numToCountMap.put(key, numToCountMap.get(key) + 1);
}
else {
numToCountMap.put(key, 1);
}
}
int numDups = 0;
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.get(key) > 1) {
numDups++;
}
}
return numDups;
}
I think you'll find the above is much faster even considering the horrible inefficiency of autoboxing and object creation.
The code you gave counts equivalences, so it adds one every time an element equals another element.
It sounds like what you want is the number of duplicate items, which is the same as (length - number of items that don't have a duplicate). I will call the latter "uniqueItems".
I would recommend the following:
// set of every item seen
Set<Integer> allItems = new HashSet<Integer>();
// set of items that don't have a duplicate
Set<Integer> uniqueItems = new HashSet<Integer>();
for(int i = 0; i < recent.length; i++) {
Integer val = i;
if(allItems.contains(val)) {
// if we've seen the value before, it is not a "uniqueItem"
uniqueItems.remove(val);
} else {
// assume the value is a "uniqueItem" until we see it again
uniqueItems.add(val);
}
allItems.add(val);
}
return recent.length - uniqueItems.size();
The below code works perfectly to find the duplicates
int array[] = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5};
HashMap<Integer,Integer> duplicates = new HashMap<Integer,Integer>();
for(int i=0; i<array.length; i++)
{
if(duplicates.containsKey(array[i]))
{
int numberOfOccurances = duplicates.get(array[i]);
duplicates.put(array[i], (numberOfOccurances + 1));
}else{
duplicates.put(array[i], 1);
}
}
Iterator<Integer> keys = duplicates.keySet().iterator();
System.out.print("Duplicates : " );
while(keys.hasNext())
{
int k = keys.next();
if(duplicates.get(k) > 1)
{
System.out.print(" "+k);
}
}
You are counting the number of pairs of indices that have equal values. What you claim to want is the total size of all sets of equal elements that have more than one element in them.
I would use a Map or similar to count the total number of appearances of a given value. At the end, iterate over the key values adding the number of appearances for each key that has more than one appearance.
int intArray[] = {5, 1, 2, 3, 4, 5, 3, 2};
String val = "";
int c = 1;
Map<Integer, Integer> nwmap = new HashMap<Integer, Integer>();
for (int i = 0; i < intArray.length; i++) {
Integer key = intArray[i];
if(nwmap.get(key) != null && nwmap.containsKey(key)){
val += " Duplicate: " +String.valueOf(key)+"\n";
}else{
nwmap.put(key, c);
c++;
}
}
LOG.debug("duplicate value:::"+val);
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class ArrayDuplicateCount {
/**
* #author:raviteja katari
*/
public static void main(String[] args) {
int intArray[] = {5, 1,4,4,4,5,1,2,1,2,5,5};
//for counting duplicate items
int c = 0;
//creating map collection to hold integers as keys and Cont as value
Map<Integer, Integer> nwmap = new LinkedHashMap<Integer, Integer>();
for (int i = 0; i <intArray.length; i++) {
//Assigning array element to key
Integer key = intArray[i];
//this code checks for elemnt if present updates count value else
//put the new Array elemnt into map and increment count
if(nwmap.containsKey(key)){
//updating key value by 1
nwmap.put(key, nwmap.get(key) + 1);
}else{
//Adding new array element to map and increasing count by 1
nwmap.put(key, c+1);
}
}
//printing map
System.out.println(nwmap);
}
}
output:
{5=4, 1=3, 4=3, 2=2}
public void TotalduplicateNumbers {
int a[] = {2,8,2,4,4,6,7,6,8,4,5};
Map<Integer,Integer> m = new HashMap<Integer,Integer>();
for(int i=0;i<a.length;i++){
if(!m.containsKey(a[i]))
{
m.put(a[i], 1);
}
else
{
m.put(a[i], (m.get(a[i])+1));
}
}
for(Integer i:m.keySet()){
System.out.println("Number "+i+" "+"Occours "+m.get(i)+" time,");
}
}
We have an array containing 11 numbers, The logic is to create a map using these no. in which KEYS of map would be the actual number that must be entered by user and no. of occournce of that actual no. would be the value of that KEY. Here, containsKey() method checks whether the map contain that key already and return boolean value true or false as applied.If it does not contain then add that key into the map and its corresponding value should be 1 otherwise key would have already be contained in map so get the value of that key using get() and increment it by 1. Finally printing the map.
OUTPUT:--
Number 2 Occours 2 time,
Number 4 Occours 3 time,
Number 5 Occours 1 time,
Number 6 Occours 2 time,
Number 7 Occours 1 time,
Number 8 Occours 2 time,