Is there a way to Dynamically populate values into hashmap - java

Im trying to populate values dynamically into a hashmap and it is taking only the last values that im keeping into the map
for (int i = 0; i < 22; i++) {
for (int j = 0; j < col.length; j++) {
String[] Temp = finval.get(i);
ls[i] = JasperRepo.getMapObject();
ls[i].put(columnsList[j], Temp[j]);
}
m.add(ls[i]);
}
Is there any way to add values dynamically?

Here is a simple demonstration. You can make this even more concise by using some advanced features of map, but the idea is the same. It separates even and odd values.
Map<String, List<Integer>> map = new HashMap<>();
String key;
for (int i = 0; i < 10; i++) {
// assign key based on value
if (i % 2 == 0) {
key = "evens";
} else {
key = "odds";
}
// retrieve or create the list for the items.
List<Integer> list = map.get(key);
if (list == null) {
list = new ArrayList<>();
map.put(key, list);
}
// add the item to the list
list.add(i);
}
map.forEach((k,v)-> System.out.println(k + " -> " + v));
It prints the following:
odds -> [1, 3, 5, 7, 9]
evens -> [0, 2, 4, 6, 8]

Do you wish to update the values of ls[i], so that they are being incremented if there are duplicate keys?
If yes, you could try this:
if (!ls[i].containsKey(columnsList[j])) {
ls[i].put(columnsList[j], Temp[j]);
} else {
ls[i].put(columnsList[j], ls[i].get(columnsList[j]) + Temp[j]);
}

Related

Sort numbers in an array without changing even numbers position using Java-8

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

Problem finding duplicate numbers in array, is my technique bad?

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(", ")) +
']';
}

Java ArrayList adding values with same Id

So I have a an array List that looks like this: <id,value,id,value,...>and I should find all the elements with the same id and add together there respected values into a result array list (value always comes after the id). At first I thought the problem was easy and went ahead and tried this:
List<String> resultList = new ArrayList<>();
for(int i = 0; i < myList.size(); i+=2){
BigInteger currentID = new BigInteger(myList.get(i));
BigInteger currentSum = new BigInteger(myList.get(i+1));
String currentId = myList.get(i);
int j = 2;
while(j < myList.size()){
if(currentId.equals(myList.get(j))){
BigInteger value2 = new BigInteger(myList.get(j+1));
currentSum = currentID.add(value2);
}
resultList.add(currentId);
resultList.add(String.valueOf(currentSum));
j+=2;
}
}
Needless to say it isn't correct, one of the many problems is that values which haven been already added together will be readded into the result array so I think they should be removed somehow in the loop. Do you guys have any suggestions how to go around this?
Assuming you can use a Map:
My initial thought it to use a Map<String, String> map = new HashMap();
Pseudo code:
For each (id,value pair) in resultList
if map.get(id) exists
add the value to the existing entry in the map
else
add a new entry in the map for (id,value)
As code (NOTE: untested and might not compile, wouldn't copy & paste directly):
Map<String, String> map = new HashMap<>();
for(int i = 0; i < myList.size(); i+=2){
String listId = resultList.get(i); //get the Id from the resultList
String listValue = resultList.get(i+1) //get the value from the resultList
if(map.get(listId) != null) { // if the map has this Id
map.put(listId, map.get(listId)+ listValue); // add the Id's list value
}
else { // if the map doesn't have this Id
map.put(listId, listValue) // add the entry to the map
}
}
You can then take the resulting map and transform is back into a list.
I'll let you write the code to take each entry in the map and add it to a new List. Google can be helpful here.
If you want to use streams you can do it like this.
Given a list like the following:
List<BigInteger> list = List.of(1,10,3,20,3,40,1,5,4,7,1,8,4,9,6,20)
.stream().mapToLong(a -> a).mapToObj(
BigInteger::valueOf).collect(Collectors.toList());
First accumulate the sums in a map with the key being the id.
Map<BigInteger, BigInteger> mapfinal =
IntStream.iterate(0, i -> i < list.size(), i -> i += 2).mapToObj(
i -> new BigInteger[] { list.get(i), list.get(i + 1)
}).collect(Collectors.groupingBy(i -> i[0],
Collectors.reducing(BigInteger.ZERO,
a -> a[1],
(a, b) -> a.add(b))));
You can stop there and just use the map, or you can convert it to a list like the one you started with of alternating id/value pairs.
List<BigInteger> listfinal = mapfinal
.entrySet()
.stream()
.flatMap(e -> Stream.of(e.getKey(), e.getValue()))
.collect(Collectors.toList());
And print the list.
System.out.println(listfinal);
[1, 23, 3, 60, 4, 16, 6, 20]
It is easiest to do this using a Map. But it can also be done without changing the input data structure, or using any intermediate data structure.
Here is an untested code sample. I have simplified the problem by using List<Integer>
List<Integer> myList = ...
List<Integer> resultList = new ArrayList<>();
for (int i = 0; i < myList.size(); i += 2) {
int id = myList.get(i);
// Check that we haven't accumulated this id already
boolean seen = false;
for (int j = 0; j < i && !seen; j += 2) {
seen = myList.get(j) == id;
}
if (seen) {
continue;
}
// Accumulate values for 'id'
int sum = myList.get(i + 1);
for (int j = i + 2; j < myList.size(); j += 2) {
if (myList.get(j) == id) {
sum += myList.get(j + 1);
}
}
// Send to output ...
resultList.add(id);
resultList.add(sum);
}
This solution is O(N^2). And since you are actually using String and BigInteger rather than Integer, that makes it even more expensive.
A solution using a Map should be O(NlogN) or O(N) depending on the map type.
Aside: It would be faster in some cases if you used resultList rather than myList in the first inner loop. But the way I did it above is more obvious ...

Remove sublists from list while iterating

I want to count number of elements and remove some if they meet a criterion. Removing using collect and removeAll doesn't work since it removes all equal elements and I want to remove a range not all.
I tried to use sublist.clear() but I get ConcurrentModificationException even though I'm using it.remove().
public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
int writelndex = 0, count=1;
List<List<Integer>> toRemove = new ArrayList<>();
for (int i = 1; i < sortedArr.size(); ++i) {
if (sortedArr.get(i-1).equals(sortedArr.get(i))) {
count++;
} else {
if(count == m) {
int nCopies = Math.min(2,m);
List<Integer> c = sortedArr.subList(writelndex + nCopies, i);
toRemove.add(c);
}
count = 1;
writelndex = i;
}
}
Iterator<List<Integer>> iterator = toRemove.iterator();
while (iterator.hasNext()) {
List<Integer> integers = iterator.next();
iterator.remove();
integers.clear();
}
return sortedArr;
}
EDIT: adding an example:
Lets say we have the following list: (1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5) and m = 3. This means that all numbers that occur m times should occur 2 times (Math.min(2,3)). So the expected result is (1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5).
EDIT 2: #ShubhenduPramanik Solved the task very elegantly.
However, it's still unclear to me why ConcurrentModificationException was thrown even though I was using iterator.remove() and how would you go about removing a sublist from a list while iterating over it.
Hope this helps:
static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
//make the count of each element
Map<Integer, Long> result = sortedArr.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
for (Map.Entry<Integer, Long> entry : result.entrySet()) {
if (entry.getValue() == m) {
// Here 2 is hard coded. You can make a variable and pass it to the method with a parameter
for (int i = 0; i < m - 2; i++)
{
sortedArr.remove(entry.getKey());
}
}
}
return sortedArr;
}
N.B: This code is not perfect as I've assumed that m>=2
If I correctly understood the task then the algorithm:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
int m = 3;
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
int numbers;
List<Integer> sortedList = new ArrayList<>();
// Fill in the list with values
for (int i = 0; i < 13; i++) {
numbers = Integer.parseInt(reader.readLine());
sortedList.add(numbers);
}
System.out.println(controlOccurrences(sortedList, m));
}
public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
int count= 1;
for (int i = 0; i < sortedArr.size(); i++) {
for (int j = 0; j < sortedArr.size(); j++) {
if (sortedArr.get(i).equals(sortedArr.get(j)) && i != j) {
count += 1;
}
}
if (count == m) {
sortedArr.remove(i);
count = 1;
} else {
count = 1;
}
}
return sortedArr;
}
}
To get the most optimized solution, you should:
1. Build a list (or set) of the indices of the values to remove
2. Move values of your original list to a new one, except the one at the listed indices.
3. Return the new list.
This way, your algorithm complexity is O(2n), which is more optimized than both previous answers. Plus, you keep given list untouched (which can be recommended according to your execution context). Last advantage, the copy is favored because each remove call on a list is potentially heavy (inner objects after removed index are moved to the left: partial hidden browsing -_- )
I won't directly give you a working code, to let you practice ;).
Note: your use-case is too complex for it, but you should look at List.removeIf() code of array list API, which is really well optimized. Here is an article talking about it: advantages of removeIf method

How to find duplicates in a java array?

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,

Categories