How do I store the values in best java collection structure - java

What type of collection structure would be best suited for below structure .
I want to create a rows of start and end positions and wanted to store it as a structure. based on the number of occurrences I want to execute a function .
Example
StartPosition Endposition
1 5
6 9
10 14
15 18
Now I want to store the the values like ( (1,5) , (6,9) , (10,14) , (15,18) )
Now I want to execute a function 4 times as I have 4 occurrences
for (i=1 , i <4 , i ++)
{
f(xyz , Startposition , endposition)
}

I suggest you use create a simple class and a List<> of this class.
public class Range{
private int start;
private int end;
// constructor
// gets and setts
}
And you would use like this:
List<Range> ranges = new ArrayList<>();
ranges.add(new Range(1,5));
ranges.add(new Range(6,9));
...
ranges.add(new Range(x,y));
for(Range range : ranges){
f(xyz, range.getStart(), range.getEnd());
}

As I understand, two dimensional array would do. Do you have any reason why you want a collection here?

Option 1: use Array. This is very simple.
int[] arr = { 1, 5, 6, 9, 10, 14, 15, 18 };
for (int i = 0; i < arr.length; i += 2) {
int start = arr[i];
int end = arr[i + 1];
// payload
}
Option 2: use TreeSet with custom comparator. A little bit more difficult, but code is more clear.
Set<Pair<Integer, Integer>> ranges = new TreeSet<>(Comparator.comparingInt((ToIntFunction<Pair<Integer, Integer>>)Pair::getKey).thenComparingInt(Pair::getValue));
ranges.add(new Pair<>(1, 5));
ranges.add(new Pair<>(6, 9));
ranges.add(new Pair<>(10, 14));
ranges.add(new Pair<>(15, 18));
for (Pair<Integer, Integer> range : ranges) {
int start = range.getKey();
int end = range.getValue();
// payload
}

You can use built in java.awt.Point class to set X,Y values. Stores those objects in either java.util.ArrayList or java.util.LinkedList

Related

How to iterate through list of lists on demand?

As the title indicates, I am looking for a solution on how to implement the getNextCombination method shown in the code snippet below.
public class Test {
private final List<List<String>> iterators;
/**
* #return null if no combination left
*/
public String[] getNextCombination() {
return null;
}
}
Assuming the attribute iterator would look like
[0]={1,2}
[1]={4,5}
[2]={7,8}
then the sequential call to the getNextCombination method should return something similar to this:
147
148
157
158
247
248
...
NULL
How can this be achieved as efficient as possible?
Thanks for any help.
The following generic lazy function to calculate all combinations do the job and works for any number of lists or any other structure
static Stream<int []> combinationsStream(final int... numElems) {
final int numCombinations = Arrays.stream(numElems) // the number of solutions is
.map(n -> n + 1) // possibles sizes
.reduce(1, (a, b) -> a * b); // product
final int[] queue = Arrays.stream(numElems).map(i -> -1).toArray(); // for every item take n elements
final int[] i = new int[]{0}; // volatile (final) integer
final Function<int [], int []> next = o -> { // compute the next combination
while (true) {
if (i[0] == numElems.length) { // if is the last position
i[0] -= 1; // we will back
return queue; // but it's a combination
}
queue[i[0]] += 1; // take one more of i[0]-th element
if (queue[i[0]] > numElems[i[0]]) // if no more of this
queue[i[0]--] = -1; // reset and go back
else
i[0] += 1; // if not, go forward
}
};
return Stream.iterate(null, next::apply) // iterate getting next over and over
.skip(1) // avoid the seed (null)
.limit(numCombinations); // limit the stream to combs number
}
since only work with indexes, you can use as follows
Let your list:
// let you list of list (from somewhere)
List<List<String>> iterators = asList(
asList("1", "2"),
asList("4", "5"),
asList("7", "8")
);
(lists could contains different number of elements)
then, to get a lazy stream with all combinations simply convert the list of list to an array of max indexes
// we get combinations in a lazy way simply with
// (you could set this stream in your private class field if you wish)
Stream<int []> lazyCombinations = combinationsStream(iterators.stream()
.mapToInt(g -> g.size() - 1).toArray());
in your case the call will be combinationsStream(1, 1, 1) since valid indexes are 0, 1 for each list.
To convert some index combination to your String output get the indexes and join
// to convert the indexes array to values (and concatenate all) you can write the function
Function<int [], String> toString = indexes -> IntStream
// for each list
.range(0, indexes.length)
// get the indexes[i]-th element
.mapToObj(i -> iterators.get(i).get(indexes[i]))
// and join
.collect(joining());
then, simply map the previous Stream<int []> to Stream<String> using that function
// now you can convert your indexes stream to your final combinations stream (all lazy)
Stream<String> lazySolutions = lazyCombinations.map(toString);
you can use the Stream in many ways (i.e. return in a Web Service lazily) but, if you wish take one by one you can convert to an iterator.
The itarator is lazy too
// if you need peek combinations on demand (not in a streaming way) convert stream to iterator
Iterator<String> lazyIterator = lazySolutions.iterator();
Then, you can take only one
// you can take one by one (e.g. inside a `getNextCombination`)
System.out.println("Only one: " + lazyIterator.next());
or as many as you consider
// or to the end
lazyIterator.forEachRemaining(System.out::println);
with output
Only one: 147
148
157
158
247
248
257
258
You can do something like this :
private final List<List<String>> iterators = Arrays.asList(Arrays.asList("1", "2"), Arrays.asList("4", "5"), Arrays.asList("7", "8"));
public void run() {
one("", 0, 0, iterators.size(), iterators.get(0).size()); // begin the iterate over
}
public void iterateOver(String before, int x, int y, int maxX, int maxY) {
List<String> secondList = iterators.get(x); // get Y value list
secondList.forEach((ss) -> {
if(x + 1 < maxX) { // go to next line
iterateOver(before + ss, x + 1, 0, maxX, iterators.get(x + 1).size());
} else if(y + 1 < maxY) {
System.out.println(before + ss); // print result
iterateOver(before + ss, x, y + 1, maxX, maxY); // go to next Y value
} else {
// this is finished
}
});
}
Output:
147
148
157
158
247
248
257
258
Warns: Arrays#asList list are not editable.
Also, I didn't make the full getNextCombination method because now you can use this code as you want to implement your prefered way to be at a combination, and go to next.

Sliding window of 10 seconds?

You are given an infinite stream of words (no spaces), each word also has an attached timestamp, starting at 0 and its in the format like 0, 1, 2, 3, 4, 5, ... , 6. We have APIs:
public class StreamClass {
public void consumeNextString(String next, int timeStamp);
public String getStrings(); // joins all strings into space seprated string using the below constraint
}
You are to implement both these functions. getStrings, specifically has the behavior that if you say had a stream like
one : 4
the: 5
hello : 12
the : 14
menlo: 15
If you got called getStrings now, it should print one hello the menlo instead of one the hello the menlo since the is duplicated at timestamp 11, 14 (current timestamp is 15). The oldest the at timestamp 5 got disregarded.
Later on, after the stream looks like:
one : 4
the: 5
hello : 12
the : 14
menlo: 15
big: 123
getStrings should print one the hello the menlo big because there are no duplicates in the last 10 second window (current timestamp is 123)
Work: I am thinking of an optimal way to do this, this is from an interview question.
The problem is, I dont see any good way of doing this other than just brute force, ie, storing every string then manually looking at the 10 second window to take out the oldest string, but surely there must be SOMETHING more optimal?
Well, here is a possible solution.
I used two Lists to hold the words and their timestamps.
The field lastTimeStamp is updated as each entry is consumed. It is used
to maintain the local window of seconds
when the last windows of time is entered, I simply iterate over the list of words removing the oldest duplicates.
after getString() is called, all lists are cleared to start the process anew.
This works for the supplied data and other data I have tested.
public class SlidingWindow10seconds {
public static void main(String[] args) {
StreamClass sc = new StreamClass();
sc.consumeNextString("one", 4);
sc.consumeNextString("the", 5);
sc.consumeNextString("hello", 12);
sc.consumeNextString("the", 14);
sc.consumeNextString("menlo", 15);
System.out.println(sc.getStrings());
sc.consumeNextString("one", 4);
sc.consumeNextString("the", 5);
sc.consumeNextString("hello", 12);
sc.consumeNextString("the", 14);
sc.consumeNextString("menlo", 15);
sc.consumeNextString("big", 123);
System.out.println(sc.getStrings());
}
Prints
one the hello menlo
one the hello the menlo big
class StreamClass {
int lastTimeStamp = 0;
final int windowSize = 10;
List<Integer> timeStamps = new ArrayList<>();
List<String> words = new ArrayList<>();
public void consumeNextString(String next, int timeStamp) {
words.add(next);
timeStamps.add(timeStamp);
lastTimeStamp = timeStamp;
}
public String getStrings() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < words.size(); i++) {
int ts = timeStamps.get(i);
// append all words if outside the window
if (ts < lastTimeStamp - windowSize) {
sb.append(words.get(i) + " ");
} else {
// Now iterate thru the list removing the oldest
// duplicates by adding in reverse order
Set<String> distinct = new LinkedHashSet<>();
for (int k = words.size()-1; k >= i; k--) {
distinct.add(words.get(k));
}
// and now reverse that using stack.
Stack<String> stk = new Stack<>();
stk.addAll(distinct);
while(!stk.isEmpty()) {
sb.append(stk.pop()+" ");
}
break;
}
}
sb.setLength(sb.length()-1);
words.clear();
timeStamps.clear();
return sb.toString();
}
}

Extracting from an Integer ArrayList using another Integer ArrayList as the index

Can I pull the values from a list such as "Values Wanted" using the list "Index" as an index to pull the specific integers from "Value Wanted"?
For Example, Index Value of 3 would pull 10201 from Value Wanted.
Index : [3, 5, 9, 12]
Value Wanted: [40000, 17956, 13689, 10201, 9216, 8281, 1296, 3969, 4356, 5776, 4660, 2025, etc.]
Create a method which takes indexes and values as argument. Iterate values for each index and take respective value.
public ArrayList extract(ArrayList indexes, ArrayList values)
{
ArrayList extracted = new ArrayList();
for(int i = 0; i < indexes.length(); i++)
{
extracted.add(values.get(indexes.get(i)));
}
return extracted;
}
you could use streams:
List<Integer> indices = Arrays.asList(3,5,9,12);
List<Integer> values = Arrays.asList(40000, 17956, 13689, 10201, 9216, 8281, 1296, 3969, 4356, 5776, 4660, 2025);
List<Integer> resultSet = indices.stream().filter(i -> i >= 0 && i < values.size())
.map(values::get).collect(Collectors.toList());
the result would be:
10201
8281
5776
note that I've used a list in the example above only for illustration purposes and the code would perfectly work for an ArrayList aswell by using:
ArrayList<Integer> resultSet = indices.stream().filter(i -> i >= 0 && i < values.size())
.map(values::get).collect(Collectors.toCollection(ArrayList::new));

Is there an Iterator-like function (or workaround) for Arrays?

I am trying to add a sequence of letters as Strings to a 2D array. So object [17] goes to endState[0][0]; [18] to endState[0][1] and so forth.
The problem I have is with the outside for loop, which just adds object at [32] to all of the cells in the matrix. Normally I would use an iterator to deal with this when using other collections, however, it is not possible with arrays as far as i am aware (I am a novice as you may have guessed).
String [][] endState = new String[4][4];
for(int i1=17;i1<33;i1++){
for(int r=0;r<endState.length;r++){
for(int c=0;c<endState.length;c++){
endState[r][c] = config.split("")[i1];
}
}
}
Any suggestions on how I can overcome this?
Many thanks.
Do you need something like that ?
String[] configs = config.split("");
String [][] endState = new String[4][4];
int i = 17;
for(int r=0;r<endState.length;r++){
for(int c=0;c<endState.length;c++){
endState[r][c] = configs[i++];
}
}
If you want to turn the letters into a gird you can do.
String[] letters = config.substring(17).split("");
String[][] endState = new String[4][];
for (int i = 0; i < endState.length; i++)
endState[i] = Arrays.copyOf(letters, i * 4, 4);
or you could do
String[][] endState = IntStream.range(0, 4)
.mapToObject(i -> Arrays.copyOf(letters, i * 4, 4))
.toArray(s -> new String[s][]);
If you use Java 8, you can do it as follows:
Arrays.asList(someArray).foreach(item -> {});
or
Arrays.asList(someArray).stream().ANY_STREAM_FUNCTION_HERE
If you want iterate your 2dim array:
Arrays.asList(someArray).foreach(item -> {
Arrays.asList(item).foreach(item2 -> {[Do your job here]})
});
You can do it more Java 7 way:
for(item : Arrays.asList(someArray)) {
...
}
Anyway you can always use Arrays.asList(someArray) to obtain a list from array.

java for-each loop for partial array

I know how to use the for-each loop to cycle through an entire array like so:
for(int d : arrayname){
do something
But how do you use the for-each loop to cycle through a partial array, like the one I am trying to do is to use the for-each to cycle through only the months of May-October, i.e. [4] - [9] to calculate the heat index. Here is a snippet of my code that shows what I am trying to do:
// create array for KeyWestTemp
double[] KeyWestTemp;
KeyWestTemp = new double[12];
// initialize array
KeyWestTemp[0] = 70.3;
KeyWestTemp[1] = 70.8;
KeyWestTemp[2] = 73.8;
KeyWestTemp[3] = 77.0;
KeyWestTemp[4] = 80.7;
KeyWestTemp[5] = 83.4;
KeyWestTemp[6] = 84.5;
KeyWestTemp[7] = 84.4;
KeyWestTemp[8] = 83.4;
KeyWestTemp[9] = 80.2;
KeyWestTemp[10] = 76.3;
KeyWestTemp[11] = 72.0;
// create array for KeyWestHumid
int[] KeyWestHumid;
KeyWestHumid = new int[12];
// initialize array
KeyWestHumid[0] = 69;
KeyWestHumid[1] = 67;
KeyWestHumid[2] = 66;
KeyWestHumid[3] = 64;
KeyWestHumid[4] = 66;
KeyWestHumid[5] = 69;
KeyWestHumid[6] = 67;
KeyWestHumid[7] = 67;
KeyWestHumid[8] = 70;
KeyWestHumid[9] = 69;
KeyWestHumid[10] = 69;
KeyWestHumid[11] = 70;
// for-each loop for calculating heat index of May - October
[0] is January and [11] is December
double[] mayOctober = Arrays.copyOfRange(KeyWestHumid, 4, 9);
and foreach mayOctober to do what you asked.
btw, it is prefered in that case to use conventional loop.
You are using the enhanced for loop, you can just use the regular for loop to achieve what you want
for(int i=START; i<=END;i++){
//do work
}
In your case it would most likely look like
int sumOfHumidity=0
for(int month i=4; i<=9;i++){
sumOfHumidity+=KeyWestHumid[month]
}
and then use sumOfHumidity however you see fit.
Other notes
KeyWestHumid is a variable, as such it should be lowerCamelCase, so
keyWestHumid, the same for keyWestTemp
The hard coding of 4 and 9 is probably undesirable, but without knowing the exact program structure it is hard to advise further than saying using the variables startMonth and endMonth is probably desirable, allowing numberOfMonths to be calculated using the two (which I expect you'll want to create an average from sumOfHumidity)
You can use a normal for loop:
for(int month=4; month<=9; month++){
KeyWestHumid[month].something();
}
You cannot use the enhanced for loop to partially iterate an array.
According to the Java language specification:
The enhanced for statement is equivalent to a basic for statement of
the form:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
VariableModifiersopt TargetType Identifier = #a[#i];
Statement
}
You can, as suggested in other answers, either create a new array (or any other collection) which contains only the elements you want to iterate or use a regular for loop.
In Java 8:
double[] array = {1, 6, 7, 3, 3, 1, 2, 8, 9, 7, 3};
Arrays.stream(array, 3, 6).forEach((d) -> {
System.out.println(d);
});
OR
IntStream.range(3, 6).mapToDouble(i -> array[i]).forEach(d -> {
System.out.println(d);
});
You could try getting away from arrays and use Lists.
public void test() {
List<Double> keyWestTemp = new ArrayList(Arrays.asList(70.3, 70.8, 73.8, 77.0, 80.7, 83.4, 84.5, 84.4, 83.4, 80.2, 76.3, 72.0));
System.out.println("Key West Temps: "+keyWestTemp);
System.out.println("Apr-Jun Temps: "+keyWestTemp.subList(3, 6));
keyWestTemp.set(4, 81.6);
System.out.println("Apr-Jun Temps: "+keyWestTemp.subList(3, 6));
}
Obviously you can iterate across the sub-lists as easily as you can print them and they shine-through to the underlying list. i.e. if you change the original list the sub-list also sees the change.

Categories