Slice a column or row from 2d Java Array - java

I'm trying to slice the columns or rows of a 2d Integer Array in Java.
I tried the following syntax array[:][0] or array[0][:] to get the first column/row. I get an error, so most probably this is not the correct syntax in Java. Is it possible to slice in any case a specific column/row in Java?

If I'm not mistaken, slicing in Python corresponds to extracting a subarray from the given array, so if you have an array like below:
int[][] vet = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
Performing the following slicing vet[0:3][1] corresponds to retrieve an array with the elements 2, 5, 8 (second column from row 0 included to row 3 excluded).
Unfortunately, in Java this is not possible, at least not "vertically" since a 2D array is basically an array of arrays. Each "row" index identifies a sub-array but in reality there are now actual rows or columns, just arrays within another array.
What you could do is to use the Arrays.copyOfRange() method to slice an array "horizontally".
Integer[][] vet = new Integer[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
Integer[] subArray = new Integer[3];
subArray = Arrays.copyOfRange(vet[1], 0, 3); //Retrieves the elements [4, 5, 6]
Instead, for slicing "vertically" you need to write a utility method:
public static void main(String[] args) {
Integer[][] vet = new Integer[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
Integer[] subArray = new Integer[3];
verticalSlicing(vet, subArray, 1, 0, 3);
System.out.println(Arrays.toString(subArrayVert)); //Prints [2, 5, 8]
}
public static <T> void verticalSlicing(T[][] vet, T[] subArray, int col, int rowStart, int rowEnd) {
if (col < 0 || col > subArray.length || (rowEnd - rowStart) > subArray.length) {
return;
}
IntStream.range(rowStart, rowEnd).forEach(i -> subArray[i] = vet[i][col]);
}

Usually a 2d array in java will look something like this:
double[][] doubleArray = new double[3][4];
So getting the first row can be:
double[] firstRow = doubleArray[0];
And getting the first column can look like this:
double[] firstColumn = new double[doubleArray.length];
for (int i = 0; i < doubleArray.length; i++) {
firstColumn[i] = doubleArray[i][0];
}

Given that you index array[x][y] you can get column x by:
int column[] = array[x].
To get row y:
int row[] = new int[array.length];
for (int i = 0; i < array.length; i++) {
row[i] = array[i][y];
}

Related

Finding indexes of 2d array elements in a sorted 2d array by columns

I have two 2D arrays of integers of the same dimension that I need to compare. I am going to explain what I need with an example where Sjm1 is the "original" array and the Sjm2 array has the same values as Sjm1 but the values of each column are ordered in increasing order (i.e. "0" is the min value of Sjm1 in column 0 so Sjm2[0][0]=0; then "70" is the next min value of Sjm1 in column 0 ⇒ Sjm2[1][0]=70; and so on). I have a method to sort a "Sjm1" array to "Sjm2".
Now I need to build an "output" array (2D array of integers) where the values in each column represent the number of the row in Sjm1 array that coincides with the elements of the column in Sjm2. For example, Output[0][0]=5 because Sjm1[0][0]=366 is Sjm2[5][0]=366; Output[1][0]=2 because Sjm1[1][0]=104 is Sjm2[2][0]=104; and so on).
Thus, for the previously presented example, the needed output must be the following:
I tried to build a method in Java where I pass the two 2D arrays of integers but is not working as needed:
public static int[][] sec(int[][] Sjm1, int[][] Sorted_Sjm2) {
int k;
int[][] output = new int[Sjm1.length][Sjm1[0].length];
for (int j = 0; j < Sjm1.length; j++) {
k = 0;
for (int m = 0; m < Sjm1[0].length; m++) {
if (Sorted_Sjm2[j][m] == Sjm1[j][m]) {
output[j][m] = k;
k++;
}
}
}
return output;
}
The output is clearly not what I need:
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
I'll be glad if someone can help me.
I think you are not updating the value of k correctly, if I understood what you need, once you find the value you are looking for just update the value of k to the index you found the value in. Note that if you have repeated values it will only take the first it found.
public static int[][] sec(int[][] Sjm1, int[][] Sorted_Sjm2) {
int k;
int[][] output = new int[Sjm1.length][Sjm1[0].length];
for (int j = 0; j < Sjm1.length; j++) {
k = 0;
for (int m = 0; m < Sjm1[0].length; m++) {
if (Sorted_Sjm2[j][m] == Sjm1[j][m]) {
k = j;
output[j][m] = k;
break;
}
}
}
return output;
}
I'm kinda new to contributing, so please let me know if I got this wrong! ><"
The problem is with your code, you're comparing both of the matrices at the same intervals (as m and j changes). What you could do, is iterate through matrix sjm2 and compare for each iteration for matrix sjm1.
i.e.
Have value of SJM1
Iterate through that column in SJM2 to find the row with the same val
Add the row number in the output.
Plus, the only way you got your output is if your Sorted_Sjm2 is the same as your Sjm1, as k was incremented to 6 every iteration.
Inside your inner loop (which sets output[j][m]) an easy way to find the matching index would be to use List.indexOf rather than searching for it yourself:
output[j][m] = Arrays.asList(Sjm2[j]).indexOf(Sjm1[j][m]);
If I get your question right, the problem is with the k variable.
It represents the row index on the second array, so when you compare the value on the two array, you should index the row of the second array with k.
Also, you should iterate the k over all rows in the current column, so the code would look like this (I modified the variables to make them more describing):
public static int[][] sec(int[][] Sjm1, int[][] Sorted_Sjm2) {
int[][] output = new int[Sjm1.length][Sjm1[0].length];
for (int row = 0; row < Sjm1.length; row++) {
for (int column = 0; column < Sjm1[0].length; column++) {
int valueToSearchFor = Sjm1[row][column];
for (int rowInSorted = 0; rowInSorted < Sorted_Sjm2.length; rowInSorted++) {
if (Sorted_Sjm2[rowInSorted][column] == valueToSearchFor) {
// Found
output[row][column] = rowInSorted;
break;
}
// Not found
output[row][column] = -1;
}
}
}
return output;
}
Note that although this code works, I doubt that it's optimal, so I would not use it for very large data sets.
At first you need to iterate on Sorted_Sjm2[j][] to find out where is the Sjm1[j][m] value so you need another for in for (int m = 0; m < Sjm1[0].length; m++). And the other thing is why you are using k?k doesn't show any thing in your array. If you want gain the sorted position you should use another variable that you declare in new for statement in
Sorted_Sjm2[j][]. Because we know you are in column j so we just need to now row number of the sorted array.
public static int[][] sec(int[][] Sjm1, int[][] Sorted_Sjm2) {
int k;
int[][] output = new int[Sjm1.length][Sjm1[0].length];
for (int j = 0; j < Sjm1.length; j++) {
for (int m = 0; m < Sjm1[0].length; m++) {
for (int d = 0; m < Sjm1[0].length; d++) {
if (Sorted_Sjm2[j][d] == Sjm1[j][m]) {
output[j][m] = d;
}
}
}
}
return output;
}
To get a matrix of row indices by columns of elements of this matrix in a sorted matrix - you can first sort the row indices of the elements of this matrix by columns and get the sorted transposed matrix of indices. Then transpose the sorted matrix back and, for each element, swap its value and column index:
int m = 7;
int n = 8;
int[][] arr1 = new int[][]{
{366, 139, 223, 312, 563, 471, 437, 2},
{104, 195, 85, 0, 377, 289, 227, 5},
{451, 221, 329, 425, 523, 591, 537, 1},
{208, 78, 0, 140, 437, 380, 286, 6},
{0, 52, 114, 84, 296, 212, 205, 3},
{70, 0, 40, 121, 194, 156, 123, 3},
{299, 351, 446, 216, 648, 685, 571, 2}};
int[][] arr2 = IntStream
// iterate over the indices
// of the rows of the array
.range(0, n)
.mapToObj(i -> IntStream
// iterate over the
// indices of the columns
.range(0, m)
.boxed()
// sort indices of the elements of the
// columns by its values in the array
.sorted(Comparator.comparingInt(j -> arr1[j][i]))
.mapToInt(Integer::intValue)
// sorted column of indices
// is a row in the new array
.toArray())
// return sorted array of indices
.toArray(int[][]::new);
// transpose the array of indices
int[][] arr3 = new int[m][n];
IntStream.range(0, m).forEach(i ->
IntStream.range(0, n).forEach(j -> {
// swap the column index and
// the value of the element
int val = arr2[j][i];
arr3[val][j] = i;
}));
// output
Arrays.stream(arr3).map(Arrays::toString).forEach(System.out::println);
Output:
[5, 3, 4, 5, 5, 4, 4, 1]
[2, 4, 2, 0, 2, 2, 2, 5]
[6, 5, 5, 6, 4, 5, 5, 0]
[3, 2, 0, 3, 3, 3, 3, 6]
[0, 1, 3, 1, 1, 1, 1, 3]
[1, 0, 1, 2, 0, 0, 0, 4]
[4, 6, 6, 4, 6, 6, 6, 2]
See also:
• Sorting 2d array of integers by column
• Finding the position of a row element in a 2d ordered array

Double Array: Out of Bounds

I am trying to write a code that finds the average of the inputs of a 2D array:
This is what I have written:
public class AverageLength
{
public static void main(String[] args)
{
int sum = 0;
int w = 0;
int[][] foobar = new int[][]
{
{0, 5, 7},
{3, 2, 4},
{8, 7, 3},
{1, 5, 3}
};
for (int i = 0; i < foobar.length; i++)
{
for (int j = 0; j <foobar[0].length; j++)
{
System.out.println(foobar[i][j]);
sum = sum + foobar[i][j];
w++;
}
} System.out.println("Average = " + sum/w);
}
}
However, if I change the array lengths and try what follows:
int[][] foobar = new int[][]
{
{0, 5, 7, 3},
{3, 3, 5, 7, 8, 4},
{8, 3},
{1, 5, 1, 2, 3}
};
it gives me the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at AverageLength.main(AverageLength.java:18)
How can I fix this issue?
change
foobar[0].length
to
foobar[i].length
when your sub arrays lengths are different you should get corresponding length
for example
{0, 5, 7, 3},
{3, 3, 5, 7, 8, 4},
{8, 3},
in this case
foobar[0].length is 4 .so when you loop through 3rd sub array {8, 3}
and when you try to access 2nd index [3rd element ] you get error
ArrayIndexOutOfBoundsException: 2
because there is no 2nd index.
and also in 2nd sub array {3, 3, 5, 7, 8, 4}, value 8 and 4 will not print because you loop 4 times .
When you check in your seccond for for array length you should use i not 0, because if you use 0 you will always get length of just first array.
for (int j = 0; j <foobar[i].length; j++)
By using foobar[0].length you are using the length of the first inner array for every inner array. Use foobar[i].length instead, which will calculate the current array's length.
By the way: Calculating averages of int arrays can be done java-internally since Java8. An example of how to use Java8's streaming API to solve this task:
import java.util.Arrays;
public class AverageLength
{
public static void main(String[] args)
{
int[][] foobar = new int[][]
{
{0, 5, 7},
{3, 2, 4},
{8, 7, 3},
{1, 5, 3}
};
System.out.print("Average = ");
System.out.println(
// convert 2D array to stream of arrays
Arrays.stream(foobar)
// flatten 2D array to 1D array
.flatMapToInt(Arrays::stream)
// let java calculate the average
.average()
// get result
.getAsDouble());
}
}
Benefits:
code is easier to understand
your program is potentially much faster
code can be easily changed to run in several threads (use .parallel())

Java - Return an array from array with two given indexes

Let's say I have an array:
int[] values = {1, 2, 3, 4, 5, 6, 7 , 8, 9, 0};
With two indexes (let's say 2 and 5), I want to be able to return array from indexes 2 to 5 from the variable values given above. The final output should be this:
newValues[] = {3, 4, 5, 6};
Also, how would this procedure be used with multi dimensional arrays?
I would have googled this, but I'm not sure what to google, so I came here.
Use java.util Arrays class. Use copyOfRange(int[] original, int from, int to) method:
newValues[] = Arrays.copyOfRange(values, 2, 6);
Try the following
public static void main(String[] args)
{
int[] values = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int start = 2, end = 5; // Index
int[] newValues = new int[end - start + 1]; // Create new array
for (int i = start; i <= end; i++) {
newValues[i - start] = values[i]; // Assign values
}
// Print newValues
for (int v : newValues) {
System.out.print(v + " ");
}
}
Output:
3 4 5 6
Try the following for 2D arrays:
public int[][] getRange(int[][] src, int x, int y, int x2, int y2) {
int[][] ret = new int[x2-x+1][y2-y+1];
for(int i = 0; i <= x2-x; i++)
for(int j = 0; j <= y2-y; j++)
ret[i][j] = src[x+i][y+j];
return ret;
}
For 1D Arrays, Arrays.copyOfRange() should be fine and for more dimensions you can simply add more params and for loops
You can use the following :
int[] values = {1, 2, 3, 4, 5, 6, 7 , 8, 9, 0};
int newValues[] = new int[4];
System.arraycopy(values,1,newValues,0,4)
Here's the complete code :
public class CopyRange {
public static void main (String...args){
int[] values = {1, 2, 3, 4, 5, 6, 7 , 8, 9, 0};
int newValues[] = new int[4];
System.arraycopy(values,1,newValues,0,4);
for (int i =0;i <newValues.length;i++)
System.out.print(newValues[i] + " ");
}
}
The System class has an arraycopy method that you can use to efficiently copy data from one array into another:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

How to work with arrays within arrays in java?

Let's say I have an int[][] anArray = new int[4][4];
And let's say that I wanted to make row 3 of anArray {1, 2, 3, 4}. Could I do that without manually assigning each individual value its value? What if it was column 2 of anArray?
I'm posting this because it's rather inconvenient to do stuff like this:
int[][] foo = new int[bar][baz];
//
//Code that uses other columns of foo
//
for (int n=0; n < bar; n++)
foo[n][1] = bin[n];
If I understand your question correctly, here is the code to assign row index 3 of anArray as {1,2,3,4} without loops:
int[][] anArray = new int[4][4];
anArray[3] = new int[] {1,2,3,4};
System.out.println(Arrays.deepToString(anArray));
Output:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 2, 3, 4]]
If you want to assign the entire row of a two-dimensional array to another (one-dimensional) array, you can simply do
int[][] foo = new int [3][3];
int[] bin={1,2,3};
foo[1] = bin;
If want to assign the column though, I am afraid that you can only do it manually...
anArray[3] = new int [] {1, 2, 3, 4}
It is basically an array of arrays and so we can add full arrays in one go:
int[][] array = new int[4][4];
for (int i = 0; i < array.length; i++) {
array[i] = new int[] { 1, 2, 3, 4 };
}
You can use a helper method to set a column:
public class MatrixTest {
public static void main(String... args) {
Integer[][] target = new Integer[3][2];
setMatrixColumn( target, 1, new Integer[]{ 1, 1, 1 } );
System.out.println( Arrays.deepToString( target ) );
}
public static <T> void setMatrixColumn(T[][] matrix, int index, T[] values) {
for ( int i = 0; i < values.length; i++ )
matrix[i][index] = values[index];
}
}

How to remove a row from a 2d array?

I have a simple array, sort of like this:
1 2 3 4 5 6 7 8 9
6 2 7 2 9 6 8 10 5
2 6 4 7 8 4 3 2 5
9 8 7 5 9 7 4 1 10
5 3 6 8 2 7 3 7 2
So, let's call this matrix[5][9]. I wish to now remove every row within this matrix that contains a certain value, in this case 10, so I am left with...
1 2 3 4 5 6 7 8 9
2 6 4 7 8 4 3 2 5
5 3 6 8 2 7 3 7 2
Here's a sample class you can run that I believe does what you're looking for. Removing rows from 2D arrays is tricky business because like #KalebBrasee said, you can't really "remove" them, but rather you have to make a whole new 2D array instead. Hope this helps!
import java.util.ArrayList;
import java.util.List;
public class Matrix {
private double[][] data;
public Matrix(double[][] data) {
int r = data.length;
int c = data[0].length;
this.data = new double[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
this.data[i][j] = data[i][j];
}
}
}
/* convenience method for getting a
string representation of matrix */
public String toString() {
StringBuilder sb = new StringBuilder(1024);
for (double[] row : this.data) {
for (double val : row) {
sb.append(val);
sb.append(" ");
}
sb.append("\n");
}
return (sb.toString());
}
public void removeRowsWithValue(final double value) {
/* Use an array list to track of the rows we're going to want to
keep...arraylist makes it easy to grow dynamically so we don't
need to know up front how many rows we're keeping */
List<double[]> rowsToKeep = new ArrayList<double[]>(this.data.length);
for (double[] row : this.data) {
/* If you download Apache Commons, it has built-in array search
methods so you don't have to write your own */
boolean found = false;
for (double testValue : row) {
/* Using == to compares doubles is generally a bad idea
since they can be represented slightly off their actual
value in memory */
if (Double.compare(value, testValue) == 0) {
found = true;
break;
}
}
/* if we didn't find our value in the current row,
that must mean its a row we keep */
if (!found) {
rowsToKeep.add(row);
}
}
/* now that we know what rows we want to keep, make our
new 2D array with only those rows */
this.data = new double[rowsToKeep.size()][];
for (int i = 0; i < rowsToKeep.size(); i++) {
this.data[i] = rowsToKeep.get(i);
}
}
public static void main(String[] args) {
double[][] test = {
{1, 2, 3, 4, 5, 6, 7, 8, 9},
{6, 2, 7, 2, 9, 6, 8, 10, 5},
{2, 6, 4, 7, 8, 4, 3, 2, 5},
{9, 8, 7, 5, 9, 7, 4, 1, 10},
{5, 3, 6, 8, 2, 7, 3, 7, 2}};
//make the original array and print it out
Matrix m = new Matrix(test);
System.out.println(m);
//remove rows with the value "10" and then reprint the array
m.removeRowsWithValue(10);
System.out.println(m);
}
}
Use System.arraycopy or use java.util.List instead of arrays. ArrayList has fast access to random elements and a slow remove method, it's the opposite with LinkedList. You have to choose for yourself.
At the and you have to recreate the array and discard the old one. Changing the dimension of an existing array is not possible - if want this type of datastructure, then you should build the matrix based on Collections (ArrayList<ArrayList<Double>>), there you can remove a row easily.
Back to arrays - the idea is to collect all rows (double[] arrays) that you want to keep, create a result array with those rows and replace the old one with the new on on Matrix:
public void doSomethingWith(Matrix in) {
List<double[]> survivingRows = new ArrayList<double[]>();
for (double[] row:in.getRows()) {
if (isAGoodOne(row)) {
survivingRows.add(row);
}
}
double[][] result = new double[survivingRows][];
for (int i = 0; i < result.length; i++) {
result[i] = survivingRows.get(i);
}
in.setArray(result);
}
You can't remove elements from the Java built-in array data structure. You'll have to create a new array that has a length one less than the first array, and copy all the arrays into that array EXCEPT the one you want to remove.
My java syntax is a little rusty, but the following, if treated as pseudocode will work
public Matrix removeRows(Matrix input) {
int[][] output = new int[input.numRows][input.numColumns]();
int i = 0;
for (int[] row : input.rows()) { // Matrix.rows() is a method that returns an array of all the rows in the matrix
if (!row.contains(10)) {
output[i] = row;
}
}
return output
My take:
import java.util.Arrays;
public class RemoveArrayRow {
private static <T> T[] concat(T[] a, T[] b) {
final int alen = a.length;
final int blen = b.length;
if (alen == 0) {
return b;
}
if (blen == 0) {
return a;
}
final T[] result = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), alen + blen);
System.arraycopy(a, 0, result, 0, alen);
System.arraycopy(b, 0, result, alen, blen);
return result;
}
public static void main(String[] args) {
double[][] d = { {11, 2, 3, 4, 5, 6, 7, 8, 9, 0},
{12, 2, 3, 4, 5, 6, 7, 8, 9, 1},
{13, 2, 3, 4, 5, 6, 7, 8, 9, 2},
{14, 2, 3, 4, 5, 6, 7, 8, 9, 3},
{15, 2, 3, 4, 5, 6, 7, 8, 9, 4} };
//remove the fourth row:
// (1)
double[][] d1 = concat(Arrays.copyOf(d, 3), Arrays.copyOfRange(d, 4, 5));
// (2)
double[][] d2 = new double[d.length - 1][d[0].length];
System.arraycopy(d, 0, d2, 0, 3);
System.arraycopy(d, 4, d2, 3, 1);
System.out.print(d1.length);
System.out.print(d2.length);
}
}
(1)
If you exclude the concat() function used for concatenating two arrays, it's done in one line:
double[][] d1 = concat(Arrays.copyOf(d, 3), Arrays.copyOfRange(d, 4, 5));
See this question as well. That's where the code for the concat() function comes from.
(2)
This method is faster and only uses already available functions.
Since it cannot avoid creating new 2D array to contain the after-removed data, firstly, create a new 2D int[][] b with same dimension as a[][]. secondly, loop through a[][], assign a to b and move b row up when a contain specific value. and sanity check the last row, which can contain specific data.
public static int[][] remove(int[][] a, int v) {
int r = a.length;
int c = a[0].length;
int[][] b = new int[r][c];
int red = 0;
boolean s = false;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
b[i - red][j] = a[i][j];
if (a[i][j] == v) {
red += 1;
if(i==r-1){
s = true;
}
break;
}
}
}
//check last row
if(s){
for(int i = r-red;i <r-red +1; i++ )
for (int j = 0; j<c; j++){
b[i][j] = 0;
}
}
return b;
}
public static void main(String[] args){
int[][] a = { {1, 2, 3, 4, 5, 6, 7, 8, 1},
{6, 2, 7, 2, 9, 6, 8, 10, 5},
{2, 6, 4, 7, 8, 4, 2, 2, 5},
{9, 8, 7, 5, 9, 7, 4, 1, 1},
{5, 3, 6, 8, 2, 7, 3, 1, 1} };
print(remove(a, 10));
}
public static void print(int[][] a) {
int r = a.length;
int c = a[0].length;
int red = 0;
for (int i = 0; i < r; i++) {
System.out.printf("\nrow %d, \n", i);
for (int j = 0; j < c; j++) {
System.out.printf("%d, ", a[i][j]);
}
}
}
This may not be an exact solution but a concept of how you can achieve it using System.arraycopy.
In the example below, I want to copy all the rows except the first row. In your case, you can skip those rows which contain 10.
String[][] src = getSheetData(service, spreadSheetId, range);
String[][] dest = new String[src.length-1][src[0].length];
for (int i = 1; i < src.length; i++) {
System.arraycopy(src[i], 0, dest[i-1], 0, src[0].length-1);
}
Reference: https://docs.oracle.com/javase/6/docs/api/java/lang/System.html#arraycopy%28java.lang.Object,%20int,%20java.lang.Object,%20int,%20int%29
You can use IntStream.noneMatch method for this purpose:
int[][] arr1 = {
{1, 2, 3, 4, 5, 6, 7, 8, 9},
{6, 2, 7, 2, 9, 6, 8, 10, 5},
{2, 6, 4, 7, 8, 4, 3, 2, 5},
{9, 8, 7, 5, 9, 7, 4, 1, 10},
{5, 3, 6, 8, 2, 7, 3, 7, 2}};
int[][] arr2 = Arrays.stream(arr1)
.filter(row -> Arrays.stream(row).noneMatch(i -> i == 10))
.toArray(int[][]::new);
// output
Arrays.stream(arr2).map(Arrays::toString).forEach(System.out::println);
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 6, 4, 7, 8, 4, 3, 2, 5]
[5, 3, 6, 8, 2, 7, 3, 7, 2]

Categories