Rank values of an Array - java

I have this input of array: int[] input = {1,3,2,2,33,1}; I need to make score for it like this output: {1,3,2,2,4,1} so the smallest number gets 1 and if there is smaller it gets 2 an so on.
another example: for input {1,10,3,44,5,2,5} -outputs-> {1,5,3,6,4,2,4}
This is my try but it does not work as expected.
public static int[] getRanksArray(int[] array) {
int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = 0; j < array.length; j++) {
if (array[j] != array[i]) {
count++;
}
}
result[i] = count + 1;
}
return result;
}

Edit: Updated to handle double rather than int input array.
First sort an array representing indices of the input array. Then walk through this array incrementing a rank counter whenever you encounter successive elements that are not equal (ideone)
public static int[] rank(double[] nums)
{
Integer[] idx = new Integer[nums.length];
for(int i=0; i<idx.length; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> (Double.compare(nums[a], nums[b])));
// Or use this for descending rank
// Arrays.sort(idx, (a, b) -> (Double.compare(nums[b], nums[a])));
int[] rank = new int[nums.length];
for(int i=0, j=1; i<idx.length; i++)
{
rank[idx[i]] = j;
if(i < idx.length - 1 && nums[idx[i]] != nums[idx[i+1]]) j++;
}
return rank;
}
Test:
System.out.println(Arrays.toString(rank(new double[] {1,3,2,2,33,1})));
System.out.println(Arrays.toString(rank(new double[] {1,10,3,44,5,2,5})));
Output:
[1, 3, 2, 2, 4, 1]
[1, 5, 3, 6, 4, 2, 4]

This can be solved using a sorted map storing lists/sets of indexes mapped by the values of the input array.
Then you can iterate over this map and fill the rank array with incrementing indexes.
Implementation:
public static int[] rank(int[] arr) {
TreeMap<Integer, List<Integer>> map = new TreeMap<>();
for (int i = 0; i < arr.length; i++) {
List<Integer> indexes = map.compute(arr[i], (k, v) -> v == null ? new ArrayList<>() : v);
indexes.add(i);
map.putIfAbsent(arr[i], indexes);
}
int[] rank = new int[arr.length];
int id = 1;
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
for(Integer i : entry.getValue()) {
rank[i] = id;
}
id++;
}
return rank;
}
Test:
int[][] d = {
{1,3,2,2,33,1},
{1,10,3,44,5,2,5}
};
for (int[] input : d) {
System.out.println(Arrays.toString(rank(input)));
}
output:
[1, 3, 2, 2, 4, 1]
[1, 5, 3, 6, 4, 2, 4]

Related

all number have been rebeated less than N times

i'm tring to return an array that have all number have been rebeated less than N times.
expected output : 1,4
this is my cod :
-- Main --
int[] data = {1, 2, 2, 3, 3, 3, 4, 5, 5};
int n = 1;
Solution.solution(data, n);
-- class Solution --
public static int[] solution(int[] data, int n) {
int l = data.length, count = 0;
int[] Narr = new int[l];
for(int i =0 ; i < l; i++){
count = 0;
for(int j=1 ; j < l ; j++){
if(data[i] == data[j]){
count++;
}
if(j == l-1){
if(count < n){
Narr[i] = data[i];
System.out.println(Narr[i]);
}
}
}
}
return Narr;
}
I would break this down to multiple steps.
First lets create a countMap that holds track of all the occurrences:
int[] data = {1, 2, 2, 3, 3, 3, 4, 5, 5};
int n = 1;
Map<Integer, Long> countMap = Arrays.stream(data).boxed()
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
System.out.println(countMap); // {1=1, 2=2, 3=3, 4=1, 5=2}
Now all we need to do is to check for the condition count <= n:
List<Integer> resultList = new ArrayList<>();
countMap.forEach((integer, count) -> {
if (count <= n) resultList.add(integer);
});
System.out.println(resultList); // [1, 4]
And last but not least converting the list back to array:
// {1, 4}
int[] resultArray = resultList.stream()
.mapToInt(Integer::intValue)
.toArray();

Value changed in ArrayList outside of for loop

I am learning Java and wanted to find the contiguous sub-array with maximum sum. I am able to find it, but when I am going outside the for loop, the value of the sub-array saved in an ArrayList changes.
public class FindingSumOfContiguousSubArray {
//code for computing sum of an array list
public int getSum (ArrayList <Integer> arraylist ) {
int sum = 0;
for (int i=0; i<arraylist.size(); i++) {
sum += arraylist.get(i);
}
return sum;
}
private ArrayList<Integer> contigiousSubArray(int [] array){
ArrayList <Integer> finalList = new ArrayList<Integer>();
int n = array.length;
int minVal = -1000;
for(int i = 0; i<n; i++) {
ArrayList<Integer> aList = new ArrayList<Integer>(); //taking local object of ArrayList
for(int j = i; j<n; j++) {
aList.add(array[j]); //{-2, 1}
int sum = getSum(aList);
//System.out.println(minVal);
if (sum > minVal) {
minVal = sum;
//finalList.clear();
finalList = aList;
System.out.println(sum);
System.out.println(finalList);
}
else continue;
}
}
System.out.println(finalList);
return finalList;
}
public static void main(String[] args) {
FindingSumOfContiguousSubArray cSA = new FindingSumOfContiguousSubArray(); //creating class object
int [] inpArray = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
ArrayList <Integer> contFinalList = cSA.contigiousSubArray(inpArray);
//System.out.println(contFinalList);
//System.out.println(cSA.getSum(contFinalList));
}
}
This code gives output:
[1, -3, 4, -1, 2, 1]
5
[4, -1, 2]
6
[4, -1, 2, 1]
[4, -1, 2, 1, -5, 4]
I am not sure why my arraylist is showing [4, -1, 2, 1, -5, 4] outside the for loop.
I'm not exactly sure what you're looking for here, but maybe try this (you don't need your summing method this way):
private static List<Integer> contigiousSubArray(int [] array){
List<Integer> finalList = new ArrayList<>();
int minVal = Integer.MIN_VALUE;
for(int i = 0; i < array.length; i++) {
List<Integer> aList = new ArrayList<Integer>(); //taking local object of ArrayList
for(int j = i; j < array.length; j++) {
aList.add(array[j]); //{-2, 1}
int sum = aList.stream()
.collect(Collectors.summingInt(Integer::intValue));
//System.out.println(minVal);
if (sum > minVal) {
minVal = sum;
finalList.clear();
finalList.addAll(aList);
}
}
}
return finalList;
}
try this :
public int contigiousSubArray(int[] arr) {
int[] result = new int[arr.length];
result[0]=arr[0];
for (int i = 1; i < arr.length; i++) {
result[i]=Math.max(result[i-1]+arr[i], arr[i]);
}
int maxSumArray = result[0];
for (int j = 1; j if(maxSumArray<result[j])
maxSumArray = result[j];
}
return maxSumArray;
}```

Print Array Combination

I have the following input
int combinationCount = 3;
int arr[] = {1, 1, 2, 2, 3};
combinationCount is {1,2,3}, combinationCount defines the number of sequence of number. For Eg: combinationCount = 3 means {1,2,3} and combinationCount = 2 means {1,2}
Array is always sorted, I want to print the output as the number of combinations as follow
[1,2,3], [1,2,3], [1,2,3], [1,2,3] //I have to iterate the whole array as it is just logic for a problem
Output Explanation (I want to print values, not index):
This is just an explanation of output which shows the index position of the value printed.
Index position of each value
[0, 2, 4], [0, 3, 4], [1, 2, 4], [1, 3, 4]
Example 2
int combinationCount = 2; // means combination is {1,2}
int arr[] = {1, 2, 2};
Print: [1,2], [1,2]
Example 3
int combinationCount = 3; // means combination is {1,2,3}
int arr[] = {1, 1, 3};
Print nothing
The program which I written is as follow:
int combinationCount = 3;
int arr[] = {1, 1, 2, 2, 3};
List<Integer> list = new ArrayList<>();
int prev = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 1) {
prev = 1;
list = new ArrayList<>();
list.add(1);
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] == prev + 1) {
prev = arr[j];
list.add(arr[j]);
} else if (arr[j] > (prev + 1)) {
break;
}
}
if (list.size() == combinationCount) {
System.out.print(list + ",");
}
} else {
break;
}
}
Output coming as
[1,2,3],[1,2,3]
which is not correct
Somewhere I am missing loop and how optimized code we can write? Any suggestions pls. Kindly let me know for any concern.
You can use Cartesian Product. I have used this answer as reference.
public class Test {
public static List<List<Integer>> product(List<List<Integer>> lists) {
List<List<Integer>> result = new ArrayList<>();
int solutions = lists.stream().mapToInt(List::size).reduce(1, (a, b) -> a * b);
for (int i = 0; i < solutions; i++) {
int j = 1;
List<Integer> tempList = new ArrayList<>();
for (List list : lists) {
tempList.add((Integer) list.get((i / j) % list.size()));
j *= list.size();
}
result.add(tempList);
}
return result;
}
public static void main(String[] args) {
int combinationCount = 2, count = 0;
int arr[] = {1, 1, 3};
Map<Integer, List<Integer>> map = new HashMap<>();
List<List<Integer>> combinations = new ArrayList<>();
for (Integer idx = 0; idx < arr.length; idx++) {
map.computeIfAbsent(arr[idx], k -> new ArrayList<>()).add(idx);
}
for (int i = 1; i <= combinationCount; i++) {
if (map.getOrDefault(i, null) != null)
count += 1;
}
if (count == combinationCount) {
List result = product(new ArrayList(map.values()));
System.out.println(result);
} else {
System.out.println("No combination found");
}
}
}
Output:
No combination found

any better solution to get duplicates and there count in an array?

I have the below code which is aimed at finding out a duplicate element in an array and printing it with its count.
I have used the below approach to solve the problem.
copy the original array into temp array
find the duplicates in original array and remove the same
copy the non duplicate array into another temp array
compare non duplicate array with original array and print out the duplicates with their counts.
For calculating the length I am using my own version of code.
It o/ps
5 4
2 3
which is correct but I want to know if we can still refine this code.
Please suggest best approach, condition is that there should not be any build in method/functions usage.
package codingpractice;
public class DuplicateCount {
public static void main(String argsp[]) throws Exception {
int array[] = { 5, 1, 2, 5, 3, 2, 2, 5, 5 };
DuplicateCount hw = new DuplicateCount();
int length = hw.length(array);
hw.duplicates(array, length);
}
public void duplicates(int array[], int length) throws Exception {
int end =length, dupCount = 0;
//copying to another array for later comparison
int[] aarray = new int[length];
for (int i = 0; i < end; i++) {
aarray[i] = array[i];
}
//finding duplicates and removing the same
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (array[i] == array[j]) {
int shiftLeft = j;
for (int k = j + 1; k < end; k++, shiftLeft++) {
array[shiftLeft] = array[k];
}
end--;
j--;
}
}
}
//copying non duplicates to another array
int[] tarray = new int[end];
for (int i = 0; i < end; i++) {
tarray[i] = array[i];
}
//Printing duplicates and there counts, comparing original array and non duplicate array
for (int i = 0; i < length(tarray); i++) {
dupCount = 0;
for (int j = 0; j < length; j++) {
if (tarray[i] == aarray[j]) {
dupCount++;
}
}
if (dupCount > 1) {
System.out.println(tarray[i] + " " + dupCount);
}
}
}
//length of array- not using inbuild function
int length(int array[]) throws Exception {
int count = 0;
int temp = 0;
try {
while (true) {
count++;
temp = array[count];
}
} catch (Exception e) {
return count;
}
}
}
Much easier technique:
Map<Integer, Integer> map = new HashMap<>();
for (int i : array) {
Integer count = map.get(i);
if (count == null) {
map.put(i, 1);
}
else {
map.put(i, count.intValue() + 1);
}
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
For the fun of it, here's a Java 8 equivalent:
Map<Integer, Integer> map = new HashMap<>();
for (int i : array) {
map.compute(i, (k, v) -> (v == null) ? 1 : v + 1);
}
map.entrySet().stream()
.filter(e -> e.getValue() > 1)
.forEach(e -> System.out.println(e.getKey() + " : " + e.getValue()));
The map.compute() call could also be replaced by
map.merge(i, 1, Integer::sum);
Just to complement JB Nizet's Java 7 solution. Here is a Java 8 solution:
public static void main(final String[] args) throws Exception {
final int[] ints = {1, 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 0, 0, 0};
final Map<Integer, Integer> count = IntStream.of(ints).
boxed().collect(HashMap::new, (map, i) -> {
map.merge(i, 1, (j, k) -> j + k);
}, HashMap::putAll);
//to print out
count.forEach((i, c) -> {System.out.println( i + " has a count of " + c);});
}
Output:
0 has a count of 3
1 has a count of 2
2 has a count of 1
3 has a count of 2
4 has a count of 2
5 has a count of 1
6 has a count of 1
7 has a count of 1
8 has a count of 1
9 has a count of 1
Using indices, create an empty array. Run on your array and increase the corresponding value at the index each time you run on it.
In your example:
int[] source = { 5, 1, 2, 5, 3, 2, 2, 5, 5 };
int[] counts = new int[6];
for (int i : source) {
counts[i]++;
}
Then your can run on the counts and you will get each element (array index) and its count (array value).

How to remove duplicates from a list using an auxiliary array in Java?

I am trying to remove duplicates from a list by creating a temporary array that stores the indices of where the duplicates are, and then copies off the original array into another temporary array while comparing the indices to the indices I have stored in my first temporary array.
public void removeDuplicates()
{
double tempa [] = new double [items.length];
int counter = 0;
for ( int i = 0; i< numItems ; i++)
{
for(int j = i + 1; j < numItems; j++)
{
if(items[i] ==items[j])
{
tempa[counter] = j;
counter++;
}
}
}
double tempb [] = new double [ items.length];
int counter2 = 0;
int j =0;
for(int i = 0; i < numItems; i++)
{
if(i != tempa[j])
{
tempb[counter2] = items[i];
counter2++;
}
else
{
j++;
}
}
items = tempb;
numItems = counter2;
}
and while the logic seems right, my compiler is giving me an arrayindexoutofbounds error at
tempa[counter] = j;
I don't understand how counter could grow to above the value of items.length, where is the logic flaw?
You are making things quite difficult for yourself. Let Java do the heavy lifting for you. For example LinkedHashSet gives you uniqueness and retains insertion order. It will also be more efficient than comparing every value with every other value.
double [] input = {1,2,3,3,4,4};
Set<Double> tmp = new LinkedHashSet<Double>();
for (Double each : input) {
tmp.add(each);
}
double [] output = new double[tmp.size()];
int i = 0;
for (Double each : tmp) {
output[i++] = each;
}
System.out.println(Arrays.toString(output));
Done for int arrays, but easily coud be converted to double.
1) If you do not care about initial array elements order:
private static int[] withoutDuplicates(int[] a) {
Arrays.sort(a);
int hi = a.length - 1;
int[] result = new int[a.length];
int j = 0;
for (int i = 0; i < hi; i++) {
if (a[i] == a[i+1]) {
continue;
}
result[j] = a[i];
j++;
}
result[j++] = a[hi];
return Arrays.copyOf(result, j);
}
2) if you care about initial array elements order:
private static int[] withoutDuplicates2(int[] a) {
HashSet<Integer> keys = new HashSet<Integer>();
int[] result = new int[a.length];
int j = 0;
for (int i = 0 ; i < a.length; i++) {
if (keys.add(a[i])) {
result[j] = a[i];
j++;
}
}
return Arrays.copyOf(result, j);
}
3) If you do not care about initial array elements order:
private static Object[] withoutDuplicates3(int[] a) {
HashSet<Integer> keys = new HashSet<Integer>();
for (int value : a) {
keys.add(value);
}
return keys.toArray();
}
Imagine this was your input data:
Index: 0, 1, 2, 3, 4, 5, 6, 7, 8
Value: 1, 2, 3, 3, 3, 3, 3, 3, 3
Then according to your algorithm, tempa would need to be:
Index: 0, 1, 2, 3, 4, 5, 6, 7, 8, ....Exception!!!
Value: 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 5, 6, 7, 8, 6, 7, 8, 7, 8, 8
Why do you have this problem? Because the first set of nested for loops does nothing to prevent you from trying to insert duplicates of the duplicate array indices!
What is the best solution?
Use a Set!
Sets guarantee that there are no duplicate entries in them. If you create a new Set and then add all of your array items to it, the Set will prune the duplicates. Then it is just a matter of going back from the Set to an array.
Alternatively, here is a very C-way of doing the same thing:
//duplicates will be a truth table indicating which indices are duplicates.
//initially all values are set to false
boolean duplicates[] = new boolean[items.length];
for ( int i = 0; i< numItems ; i++) {
if (!duplicates[i]) { //if i is not a known duplicate
for(int j = i + 1; j < numItems; j++) {
if(items[i] ==items[j]) {
duplicates[j] = true; //mark j as a known duplicate
}
}
}
}
I leave it to you to figure out how to finish.
import java.util.HashSet;
import sun.security.util.Length;
public class arrayduplication {
public static void main(String[] args) {
int arr[]={1,5,1,2,5,2,10};
TreeSet< Integer>set=new TreeSet<Integer>();
for(int i=0;i<arr.length;i++){
set.add(Integer.valueOf(arr[i]));
}
System.out.println(set);
}
}
You have already used num_items to bound your loop. Use that variable to set your array size for tempa also.
double tempa [] = new double [num_items];
Instead of doing it in array, you can simply use java.util.Set.
Here an example:
public static void main(String[] args)
{
Double[] values = new Double[]{ 1.0, 2.0, 2.0, 2.0, 3.0, 10.0, 10.0 };
Set<Double> singleValues = new HashSet<Double>();
for (Double value : values)
{
singleValues.add(value);
}
System.out.println("singleValues: "+singleValues);
// now convert it into double array
Double[] dValues = singleValues.toArray(new Double[]{});
}
Here's another alternative without the use of sets, only primitive types:
public static double [] removeDuplicates(double arr[]) {
double [] tempa = new double[arr.length];
int uniqueCount = 0;
for (int i=0;i<arr.length;i++) {
boolean unique = true;
for (int j=0;j<uniqueCount && unique;j++) {
if (arr[i] == tempa[j]) {
unique = false;
}
}
if (unique) {
tempa[uniqueCount++] = arr[i];
}
}
return Arrays.copyOf(tempa, uniqueCount);
}
It does require a temporary array of double objects on the way towards getting your actual result.
You can use a set for removing multiples.

Categories

Resources