MultiDimensional ArrayList in kmeans clustering algorithm - java

I am trying to implement kmeans algorithm for a certain Music Recommendation System in Java.
I have generated 2 arrays,playsFinal[](the total play-count of an artist by all users in the dataset) and artFinal[] (the unique artists in the entire dataset) . The playcount of every artFinal[i] is playsFinal[i]. For k,I have chosen kclusters=Math.sqrt(playsFinal.length)/2.
I have an array clusters[kclusters][playsFinal.length] and the first position clusters[i][0] for every 0<i<kclusters is filled with a certain value,which is basically the initial mean as in kmeans algorithm.
int j = 0;
for (int i = 0; i < n && j < kclusters; i += kclusters) {
clusters[j][0] = weighty[j];//initial means
System.out.println(clusters[j][0]);
j++;
}
Here,weight[] is a certain score given to every artist.
Now,in the following function I am returning the index,ie,which cluster the plays[i] should be added to.
public static int smallestdistance(double a, double[][] clusters) {
a = (double) a;
double smallest = 0;
double d[] = new double[kclusters];
for (int i = 0; i < kclusters; i++) {
d[i] = a - clusters[i][0];
}
int index = -1;
double d1 = Double.POSITIVE_INFINITY;
for (int i = 0; i < d.length; i++)
if (d[i] < d1) {
d1 = d[i];
index = i;
}
return index;
}
If not obvious,I am finding the minimum distance between playsFinal[i] and the initial element in every clusters[j][0] and the one that is the smallest,I am returning its index (kfound). Now at the index of the clusters[kfound][] I want to add the playsFinal[i] but here is where I am stuck. I can't use .add() function like in ArrayList. And I guess using an ArrayList would be way better. I have gone through most of the articles on ArrayList but found nothing that could help me. How can I implement this using a multidimensional ArrayList?
Thanks in advance.
My code is put together as follows:
int j = 0;
for (int i = 0; i < n && j < kclusters; i += kclusters) {
clusters[j][0] = weighty[j];//initial means
System.out.println(clusters[j][0]);
j++;
}
double[] weighty = new double[artFinal.length];
for (int i = 0; i < artFinal.length; i++) {
weighty[i] = (playsFinal[i] * 10000 / playsFinal.length);
}
n = playsFinal.length;
kclusters = (int) (Math.sqrt(n) / 2);
double[][] clusters = new double[kclusters][playsFinal.length];
int j = 0;
for (int i = 0; i < n && j < kclusters; i += kclusters) {
clusters[j][0] = weighty[j];//initial means
System.out.println(clusters[j][0]);
j++;
}
int kfound;
for (int i = 0; i < playsFinal.length; i++) {
kfound = smallestdistance(playsFinal[i], clusters);
//HERE IS WHERE I AM STUCK. I want to add playsFinal[i] to the corresponding clusters[kfound][]
}
}
public static int smallestdistance(double a, double[][] clusters) {
a = (double) a;
double smallest = 0;
double d[] = new double[kclusters];
for (int i = 0; i < kclusters; i++) {
d[i] = a - clusters[i][0];
}
int index = -1;
double d1 = Double.POSITIVE_INFINITY;
for (int i = 0; i < d.length; i++)
if (d[i] < d1) {
d1 = d[i];
index = i;
}
return index;
}

Java's "multidimensional arrays" are really just arrays whose elements are themselves (references to) arrays. The ArrayList equivalent is to create a list containing other lists:
List<List<Foo>> l = new ArrayList<>(); //create outer ArrayList
for (int i = 0; i < 10; i++) //create 10 inner ArrayLists
l.add(new ArrayList<Foo>());
l.get(5).add(foo1); //add an element to the sixth inner list
l.get(5).set(0, foo2); //set that element to a different value
Unlike arrays, the lists are created empty (as any list), rather than with some specified number of slots; if you want to treat them as drop-in replacements for multidimensional arrays, you have to fill them in manually. This implies your inner lists can have different lengths. (You can actually get "ragged" multidimensional arrays by only specifying the outer dimension (int[][] x = new int[10][];), then manually initializing the slots (for (int i = 0; i < x.length; ++i) x[i] = new int[i]; for a "triangular" array), but the special syntax for multidimensional array creation strongly predisposes most programmers to thinking in terms of "rectangular" arrays only.)

Related

How do I print nested ArrayLists?

My fourth for loop, for (int y), keeps printing the first m elements over and over again, how can i fix it so that it prints m elements at a time but not the same ones?
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
ArrayList<String> myname = new ArrayList<String>(n);
ArrayList<Integer> myscore = new ArrayList<Integer>(m);
for (int i = 0; i < n; i++) { //swimmers
myname.add(input.next());
for (int j = 0; j < m; j++) { //judges
myscore.add(input.nextInt());
}
}
for (int x = 0; x < n; x++) { //name
System.out.println(myname.get(x));
for (int y = 0; y < m; y++) { //score
System.out.println(myscore.get(y));
}
}
Based on your code it seems that you have ‘n’ number of swimmers, each with ‘m’ number of scores. You are storing the names of the ‘n’ swimmers in an ArrayList, which is bad because you know the number will never change. A better approach to this would be to declare myname as a String[] of size n, and instead of calling myname.get(x) you would later call myname[x].
This however, is only symptomatically related to the problem at hand. You are storing all of your score results inside a single ArrayList. A better solution is to generate ‘n’ number of arrays (which is what I assume you would like to do based on the title of this question). This can be done by simply declaring
allScores[][] = new int[n][m]
This would let you access the values for swimmer number ‘n’ with allScores[n]. If this isn’t what you actually wanted to do then you can simply offset the values in your last get statement by the number of scores you’ve already processed (x*n).
TLDR: Change the line in your last for loop to read:
System.out.println(myscore.get(y + x*n)
Because you have a list myscore of n*m length not only m like you thought. You are adding at the end of the list every score.
So you have n blocks of m elements in the list. You could still print the value with
for(int y = x * m, to = x*m + m; y < to; ++y){
System.out.println(myscore.get(y));
}
class ScoreHolder{
String name = "";
ArrayList<Integer> scores = new ArrayList<Integer>;
public ScoreHolder(String name){
this.name = name
}
}
And then
ScoreHolder[] scores = new ScoreHolder[n];
for (int i = 0; i < n; i++) { //swimmers
scores[i] = new ScoreHolder(input.next());
for (int j = 0; j < m; j++) { //judges
scores[i].scores.add(input.nextInt());
}
}
for (int x = 0; x < n; x++) { //name
System.out.println(scores[x].name);
for (int y = 0; y < m; y++) { //score
System.out.println(scores[x].scores.get(y));
}
}
It won't be just easy to work with now but also a lot easier to make any changes or do anything else you want.
What I have done is simply created a holder class which will hold the swimmer's name and a list of all his scores.
This abstraction will now help you in getting the scores of the swimmers or doing anything else you now want with it.

Adding jagged arrays beginner

I'm a beginner at java at struggling with this:
I am trying to sum two jagged arrays ( n and m, both double [][]) of the same size (each is length 3 at the first level, then of length x-1,x and x-1 respectively at the second level).
The problem I'm having is to specify the length that each array within the jagged array should be, at the moment my code is producing an n x n array because I've specified the length as n[1] rather than as a parameter, but if I try and use sum[i].length=n[i].length I get the error, "cannot assign value to final variable". So I know this part is wrong but I don't know what is right...
Thanks for the help!
My code:
else if (isValidTridiagonal(m)== true && isValidTridiagonal (n) == true)
{
int size = n[1].length; /** specifying all lengths to be x where they shouldnt be*/
sum = new double[3][size];
for (int i = 0; i < n.length; i++)
{
for(int j = 0; j< n[i].length; j++)
{
sum [i][j]= n[i][j] + m [i][j];
}
}
return sum;
}
There is some missing information. As far as I can tell there are two things you need to fix. You seem to have "sum" as a final variable already defined in your code.
Secondly, you are declaring a new array that is 3xsize big. If you want a jagged array in that sence, you must leave one of the brackets empty and in the first loop insert a new array of the wanted size.
double[][] sum = new double[3][]; //Make sure this is unique within the scope
for(int i = 0; i < 3; i++) { //if you want dynamic scaling you'll need to replace 3 in the array as well.
int size = n[i].length; //size of the new row
sum[i] = new double[size]; // Inserting a new array of the wanted size
for(int j = 0; j< sum[i].length; j++)
{
sum[i][j]= n[i][j] + m[i][j];
}
}
return sum;
The problem is probably with this line:
sum = new double[3][size];
Here you create an incorrect, non-jagged array of size [3][2]
When you try to set sum[1][2] (2nd, 3rd index), you will not be able to.
Otherwise, the code looks correct and I got a sum to work using this:
public static void main(String[] args) {
int[][] n = new int[3][];
n[0] = new int[2];
n[0][0] = 1;
n[1] = new int[3];
n[2] = new int[2];
int[][] m = new int[3][];
m[0] = new int[2];
m[1] = new int[3];
m[1][2] = 1;
m[2] = new int[2];
int[][] sum = new int[3][];
sum[0] = new int[2];
sum[1] = new int[3];
sum[2] = new int[2];
for (int i = 0; i < n.length; i++) { // n.length will be 3
for (int j = 0; j < n[i].length; j++) { // n[i].length will be 2, 3 and 2
sum[i][j] = n[i][j] + m[i][j];
}
}
System.out.println("Sum: ");
for (int i = 0; i < sum.length; i++) {
for (int j = 0; j < sum[i].length; j++) {
System.out.print(sum[i][j] + "|");
}
System.out.println();
}
}
This will print off:
Sum:
1|0|
0|0|1|
0|0|

Is there a way to return an array into another array?

Is there a way to return an array into another array.
I have a multidimensional array which I am using a method combineArrays(Comparable[][] x) to combine into another 1D array.
Normally I'd just create the 1D array in a higher scope, but I've painfully learned that Comparable arrays need a dimension when initialized and the combineArrays() is responsible for determining the size of the mutliarray.
Please be kind, I'm not done yet.
The purpose of the program itself is to accept an array of objects and find a common list of object which exist in each row. The trick is the findCommonElements() must do so in either O(nlogn) or O(n) time
/*
* combs through the original array to find the shortest row which must hold
* the least # of common objects
*/
public static int findSmallestRow(Comparable[][] queries) {
int array_length = 0;
int indexOfMaster = 0;
array_length = queries[0].length; // sets variable to initial arrays row
// length
for (int i = 0; i < queries.length; i++) { // iterates through each row
// comparing size of each
// row
if (queries[i].length <= array_length) { // ensures the 1st row is,
// at minimum, the
// master array
array_length = queries[i].length;
indexOfMaster = i;
}
}
return indexOfMaster;
}
public static void findCommonElements(Comparable[][] queries){
Comparable[] new_query = combineArray(queries);
for(int a = 0; a<new_query.length; a++){
System.out.println(new_query[a]);
}
//Arrays.sort(new_query);
int query_length = new_query.length;
int masterIndex = findSmallestRow(queries);
Comparable extracted[] = new Comparable[queries[masterIndex].length];
System.arraycopy(queries[masterIndex], 0, extracted, 0,
extracted.length);
Comparable[] intermediate_query = new Comparable[masterIndex];
int nonquery_length = extracted.length;
int counter = 0;
int counter2 = 0;
int query_index = 0;
int nonquery_index = 0;
int i =0;
int j = 0;
while(i < nonquery_length && j < query_length){
if(extracted[nonquery_index].compareTo(new_query[query_index])>0){
query_index++;
}
if(extracted[nonquery_index].compareTo(new_query[query_index])<0){
nonquery_index++;
}
if(extracted[nonquery_index].compareTo(new_query[query_index])==0){
counter++;
if(counter == queries.length){
intermediate_query[counter2] = extracted[nonquery_index];
counter2++;
}
}
}
Comparable common_list[] = new Comparable[counter2];
for(int k = 0; k<counter2; k++){
common_list[k] = intermediate_query[k];
System.out.println(common_list[i]);
}
}
//gets size of query array, even if not uniform
public static Comparable[] combineArray(Comparable[][]queries){
int length = queries.length;
ArrayList rows = new ArrayList();
for(int i = 0; i< length; i++){
for(int k = 0; k<queries[i].length; k++){
rows.add("");
}
}
int query_size = rows.size();
Comparable[] new_query = new Comparable[query_size];
int new_query_counter = 0;
for(int i = 0; i< length; i++){
for(int k = 0; k<queries[i].length; k++){
new_query[new_query_counter] = queries[i][k];
}
}
return new_query;
}
This computes the set intersection of all the rows of the array.
public static Set<Comparable<?>> common( Comparable<?>[][] a ){
Set<Comparable<?>> inter = new HashSet<>( Arrays.asList( a[0] ) );
for( int i = 1; i < a.length; ++i ){
inter.retainAll( new HashSet<>( Arrays.asList( a[i] ) ) );
}
return inter;
}
It is possible that the original idea is to retain repeated elements, i.e., if there are two 'x' in each row, the result should also contain two 'x'. The short solution given hear uses sets, which do not store repetition of equal elements. - But here is a library where you find HashMultiSet, and the code will remain basically the same except for the types of inter and result.
import org.apache.commons.collections4.multiset.HashMultiSet;

How to create multiple arrays with a loop?

I am having trouble creating multiple arrays with a loop in Java. What I am trying to do is create a set of arrays, so that each following array has 3 more numbers in it, and all numbers are consecutive. Just to clarify, what I need to get is a set of, let's say 30 arrays, so that it looks like this:
[1,2,3]
[4,5,6,7,8,9]
[10,11,12,13,14,15,16,17,18]
[19,20,21,22,23,24,25,26,27,28,29,30]
....
And so on. Any help much appreciated!
Do you need something like this?
int size = 3;
int values = 1;
for (int i = 0; i < size; i = i + 3) {
int[] arr = new int[size];
for (int j = 0; j < size; j++) {
arr[j] = values;
values++;
}
size += 3;
int count = 0;
for (int j : arr) { // for display
++count;
System.out.print(j);
if (count != arr.length) {
System.out.print(" , ");
}
}
System.out.println();
if (i > 6) { // to put an end to endless creation of arrays
break;
}
}
To do this, you need to keep track of three things: (1) how many arrays you've already created (so you can stop at 30); (2) what length of array you're on (so you can create the next array with the right length); and (3) what integer-value you're up to (so you can populate the next array with the right values).
Here's one way:
private Set<int[]> createArrays() {
final Set<int[]> arrays = new HashSet<int[]>();
int arrayLength = 3;
int value = 1;
for (int arrayNum = 0; arrayNum < 30; ++arrayNum) {
final int[] array = new int[arrayLength];
for (int j = 0; j < array.length; ++j) {
array[j] = value;
++value;
}
arrays.add(array);
arrayLength += 3;
}
return arrays;
}
I don't think that you can "create" arrays in java, but you can create an array of arrays, so the output will look something like this:
[[1,2,3],[4,5,6,7,8,9],[10,11,12,13...]...]
you can do this very succinctly by using two for-loops
Quick Answer
==================
int arrays[][] = new int[30][];
for (int j = 0; j < 30; j++){
for (int i = 0; i < (j++)*3; i++){
arrays[j][i] = (i++)+j*3;
}
}
the first for-loop tells us, via the variable j, which array we are currently adding items to. The second for-loop tells us which item we are adding, and adds the correct item to that position.
All you have to remember is that j++ means j + 1.
Now, the super long-winded explanation:
I've used some simple (well, I say simple, but...) maths to generate the correct item each time:
[1,2,3]
here, j is 0, and we see that the first item is one. At the first item, i is also equal to 0, so we can say that, here, each item is equal to i + 1, or i++.
However, in the next array,
[4,5,6,7,8,9]
each item is not equal to i++, because i has been reset to 0. However, j=1, so we can use this to our advantage to generate the correct elements this time: each item is equal to (i++)+j*3.
Does this rule hold up?
Well, we can look at the next one, where j is 2:
[10,11,12,13,14...]
i = 0, j = 2 and 10 = (0+1)+2*3, so it still follows our rule.
That's how I was able to generate each element correctly.
tl;dr
int arrays[][] = new int[30][];
for (int j = 0; j < 30; j++){
for (int i = 0; i < (j++)*3; i++){
arrays[j][i] = (i++)+j*3;
}
}
It works.
You have to use a double for loop. First loop will iterate for your arrays, second for their contents.
Sor the first for has to iterate from 0 to 30. The second one is a little less easy to write. You have to remember where you last stop and how many items you had in the last one. At the end, it will look like that:
int base = 1;
int size = 3;
int arrays[][] = new int[30][];
for(int i = 0; i < 30; i++) {
arrays[i] = new int[size];
for(int j = 0; j < size; j++) {
arrays[i][j] = base;
base++;
}
size += 3;
}

Iteration sum in a linkedlist in java

I have 3 linked lists, in java with this values:
LinkedList<Double> simTarget = new LinkedList<Double>();
LinkedList<Double> simSource = new LinkedList<Double>();
LinkedList<Double> results = new LinkedList<Double>();
simTarget.add(0.5);
simTarget.add(0.1);
simTarget.add(1.0);
simSource.add(0.5);
simSource.add(0.1);
simSource.add(1.0);
I need to perform an iteractive sum in these lists and the results I stored in the "results", for example:
for (int i = 0; i < simTarget.size(); i++)
{
for (int j = 0; j < simSource.size(); j++)
{
results.add((simTarget.get(i) + (simSource.get(j) * 0.5)/3));
}
}
So, this is my problem: with the linkedlist "results" is that I need to perform again a new iteration but with the same values of the simSource, like this:
for (int i = 0; i < results.size(); i++)
{
for (int j = 0; j < simSource.size(); j++)
{
System.out.println(results.get(i) + (simSource.get(j) * 0.5)/3);
}
}
this iteration need performing (itself) in "x" times, for example: 70 times or 80 times or 1000 times. And just the values of the "results" linkedlist shall increase.
How to perform and to develop this iteration by x times?
Thank you very much.
Because Double is both final and immutable, you will have to encapsulate Double in a custom class, 'Value' for example. Then, you will update the Double field in the Value class each time you do a summation. Therefore, only the object of type Value strored in results will be updated.
for(int x = 0;x< 1000;x++){
for (int i = 0; i < results.size(); i++)
{
for (int j = 0; j < simSource.size(); j++)
{
Value buffer = results.get(i);
buffer.doubleField += (simSource.get(j) * 0.5)/3;
//System.out.println(results.get(i) + (simSource.get(j) * 0.5)/3);
}
}
}
BTW, since you are accessing the LinkedList by index, it will be better to use an ArrayList instead.

Categories

Resources