I have a table with hundred' of record where a field is paired with a similar field based on an id. I want to know what is a good data structure for keeping frequency counts for the number of times a pair has appeared together irrespective of the order they appeared in.
Sample data:
ID Feature
5 F1
5 F2
6 F1
6 F2
7 F3
7 F1
7 F2
8 F1
9 F1
10 F1
The sample output is:
F1 F2 F3
F1 0 3 1
F2 3 0 1
F3 1 1 0
One option is to sort all features and use a 2-dimensional int array to represent the pairwise data but then 2/3's of the array is useless/duplicate. For example array[i][i] = 0 and array[i][j] = array[j][i]. Given that I have hundreds of features, this approach won't work.
I thought of using a map but then the key needs to represent a pair e.g. (F1,F3). I am hoping for other solutions too. If there are none I will use a map.
Create a class, say MyPair to use for hash keys that stores pairs of your items and overrides Object#equals(...) (and Object#hashCode()) so that order doesn't matter (e.g. by ordering lexicographically).
Create a Map<MyPair,Integer> to store the frequency count of your pairs.
class MyPair {
public final String feature1;
public final String feature2;
public MyPair(String s1, String s2) {
// Order features so comparison is order-independent.
if (s1.compareTo(s2) <= 0) { // TODO: null check
feature1 = s1;
feature2 = s2;
} else {
feature1 = s2;
feature2 = s1;
}
}
#Override public int hashCode() {
return (s1 + s2).hashCode(); // TODO: cache for performance.
}
#Override public boolean equals(that) {
return (that instanceof MyPair)
&& (that.feature1.equals(this.feature1))
&& (that.feature2.equals(this.feature2));
}
}
Then can hash pairs as expected:
Map<MyPair,Integer> freq = new HashMap<MyPair,Integer>();
MyPair pair1 = new MyPair("F1", "F2");
freq.get(pair1); // => null
freq.put(pair1, 1);
MyPair pair2 = new MyPair("F2", "F1");
freq.get(pair2); // => 1
This is simple algorithm. I assume that data is initially sorted. It is not maybe written as good as I wanted to be, but It must only shows you the proper path :)
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class NeighborListExample {
static class Pair {
private String feature;
private int cnt = 1;
Pair(String feature) {
this.feature = feature;
}
void incr() {
cnt++;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((feature == null) ? 0 : feature.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if (feature == null) {
if (other.feature != null)
return false;
} else if (!feature.equals(other.feature))
return false;
return true;
}
#Override
public String toString() {
return "(" + feature + ", " + cnt + ")";
}
}
static Map<String, List<Pair>> feature2neighbors = new HashMap<>();
private static int getId(Object[][] data, int i) {
return ((Integer) data[i][0]).intValue();
}
private static String getFeature(Object[][] data, int i) {
return data[i][1].toString();
}
private static void processFeatures(String[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (i != j) {
List<Pair> pairs = feature2neighbors.get(array[i]);
if (pairs == null) {
pairs = new LinkedList<>();
feature2neighbors.put(array[i], pairs);
}
Pair toAdd = new Pair(array[j]);
int index = pairs.indexOf(toAdd);
if (index == -1) {
pairs.add(toAdd);
} else {
pairs.get(index).incr();
}
}
}
}
}
static void print(Map<String, List<Pair>> feature2neighbors) {
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, List<Pair>> e : feature2neighbors.entrySet()) {
builder.append(e.getKey()).append(" -> ");
Iterator<Pair> it = e.getValue().iterator();
builder.append(it.next().toString());
while(it.hasNext()) {
builder.append(" ").append(it.next().toString());
}
builder.append("\n");
}
System.out.println(builder.toString());
}
public static void main(String[] args) {
//I assume that data is sorted
Object[][] data = { { 5, "F1" }, //
{ 5, "F2" }, //
{ 6, "F1" }, //
{ 6, "F2" }, //
{ 7, "F3" }, //
{ 7, "F1" }, //
{ 7, "F2" }, //
{ 8, "F1" }, //
{ 9, "F1" }, //
{ 10, "F1" }, //
};
List<String> features = new LinkedList<>();
int id = getId(data, 0);
for (int i = 0; i < data.length; i++) {
if (id != getId(data, i)) {
processFeatures(features.toArray(new String[0]));
features = new LinkedList<>();
id = getId(data, i);
}
features.add(getFeature(data, i));
}
print(feature2neighbors);
}
}
Out:
F1 -> (F2, 3) (F3, 1)
F3 -> (F1, 1) (F2, 1)
F2 -> (F1, 3) (F3, 1)
Related
I'm working with DFS solver on 8 puzzle game. This code print all children from the tree until the correct state, but I want to print only the correct solution.
My output:
120
345
678
125
340
678
102
345
678
125
348
670
125
304
678
142
305
678
012
345
678
Expected output:
120
345
678
102
345
678
012
345
678
Code:
public class puzzle {
public static LinkedHashSet<String> OPEN = new LinkedHashSet<String>();
public static HashSet<String> CLOSED = new HashSet<String>();
public static boolean STATE = false;
public static void main(String args[]) {
int statesVisited = 0;
String start = "120345678";
String goal = "012345678";
String X = "";
String temp = "";
OPEN.add(start);
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
print(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS");
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = down(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = left(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
temp = right(X, pos);
if (!(temp.equals("-1")))
OPEN.add(temp);
}
}
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
DFS returns the first path it finds. To get the shortest path use BFS.
You can use a map
private static Map<String, List<String>> paths = new HashMap<>();
to map each node (state) to the path that led to it:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
public class puzzle {
private static LinkedHashSet<String> OPEN = new LinkedHashSet<>();
private static HashSet<String> CLOSED = new HashSet<>();
private static Map<String, List<String>> paths = new HashMap<>();
public static boolean STATE = false;
public static void main(String args[]) {
String start = "120345678";
String goal = "012345678";
String X = "";
String temp = "";
OPEN.add(start);
paths.put(start, Arrays.asList(start));
while (OPEN.isEmpty() == false && STATE == false) {
X = OPEN.iterator().next();
OPEN.remove(X);
print(X);
int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE
if (X.equals(goal)) {
System.out.println("SUCCESS" +"\n" + paths.get(X));
STATE = true;
} else {
// generate children
CLOSED.add(X);
temp = up(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = down(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = left(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
temp = right(X, pos);
if (!temp.equals("-1")) {
OPEN.add(temp);
updatePaths(temp, paths.get(X));
}
}
}
}
static void updatePaths(String s, List<String> path){
if(paths.containsKey(s)) return;
List<String> newPath = new ArrayList<>(path);
newPath.add(s);
paths.put(s, newPath);
}
/*
* MOVEMENT UP
*/
public static String up(String s, int p) {
String str = s;
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p - 3) + '0' + newS.substring(p - 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT DOWN
*/
public static String down(String s, int p) {
String str = s;
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p + 3) + '0' + newS.substring(p + 4);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT LEFT
*/
public static String left(String s, int p) {
String str = s;
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p - 1) + '0' + newS.substring(p);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
/*
* MOVEMENT RIGHT
*/
public static String right(String s, int p) {
String str = s;
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, p + 1) + '0' + newS.substring(p + 2);
}
// Eliminates child of X if its on OPEN or CLOSED
if (!OPEN.contains(str) && CLOSED.contains(str) == false)
return str;
else
return "-1";
}
public static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
Online code can be reviewed and executed here and a refactored version here
We need somehow save relation between steps to find only steps from successful path.
Here is my solution:
public class Puzzle {
public static LinkedHashSet<Step> open = new LinkedHashSet<>();
public static HashSet<Step> closed = new HashSet<>();
public static boolean problemSolved = false;
private static class Step {
final String data;
Step previous = null;
Step(String data) {
this.data = data;
}
Step(Step previous, String data) {
this.previous = previous;
this.data = data;
}
public String getData() {
return data;
}
public Step getPrevious() {
return previous;
}
#Override
public String toString() {
return new StringBuilder()
.append(data.substring(0, 3))
.append("\r\n")
.append(data.substring(3, 6))
.append("\r\n")
.append(data.substring(6, 9))
.toString();
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Step)) {
return false;
}
if (obj == this) {
return true;
}
return this.getData().equals(((Step) obj).getData());
}
#Override
public int hashCode() {
return this.getData().hashCode();
}
}
public static void main(String args[]) {
int statesVisited = 0;
Step startStep = new Step("120345678");
Step goalStep = new Step("012345678");
Step currentStep;
open.add(startStep);
while (!open.isEmpty() && !problemSolved) {
currentStep = open.iterator().next();
open.remove(currentStep);
// print(currentStep);
if (currentStep.equals(goalStep)) {
System.out.println("SUCCESS PATH: \r\n");
printSuccessPath(
getSuccessPathFromFinishStep(currentStep) // here currentStep is finish step
);
problemSolved = true;
} else {
// generate children
closed.add(currentStep);
Step nextStep = up(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = down(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = left(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
nextStep = right(currentStep);
if (nextStep != null) {
open.add(nextStep);
}
}
}
}
/*
* MOVEMENT UP
*/
public static Step up(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (!(p < 3)) {
char a = str.charAt(p - 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT DOWN
*/
public static Step down(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (!(p > 5)) {
char a = str.charAt(p + 3);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT LEFT
*/
public static Step left(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (p != 0 && p != 3 && p != 7) {
char a = str.charAt(p - 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
/*
* MOVEMENT RIGHT
*/
public static Step right(Step step) {
int p = step.getData().indexOf('0');
String str = step.getData();
if (p != 2 && p != 5 && p != 8) {
char a = str.charAt(p + 1);
String newS = str.substring(0, p) + a + str.substring(p + 1);
str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);
}
Step nexStep = new Step(step, str); // Creates new step with step as previous one
// Eliminates child of X if its on open or closed
if (!open.contains(nexStep) && !closed.contains(nexStep))
return nexStep;
else
return null;
}
private static void print(Step s) {
System.out.println(s);
System.out.println();
}
private static void printSuccessPath(List<Step> successPath) {
for (Step step : successPath) {
print(step);
}
}
private static List<Step> getSuccessPathFromFinishStep(Step finishStep) {
LinkedList<Step> successPath = new LinkedList<>();
Step step = finishStep;
while (step != null) {
successPath.addFirst(step);
step = step.getPrevious();
}
return successPath;
}
}
I've refactored your code a bit. And introduced new class Step which allows us to save relation between current step and previous one.
Logic is a bit complicated, but feel free to ask additional question if something if not clear for you)
And, by the way, here is the result:
SUCCESS PATH:
120
345
678
102
345
678
012
345
678
So, a clean(er) solution that does what you've asked for looks like this:
package basic;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final String data;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
return result;
}
public Node getPrevious() {
return previous;
}
public String getData() {
return data;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
public Node(String data) {
this.data = data;
this.previous = null;
}
public Node(String data, Node previous) {
this.data = data;
this.previous = previous;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>();
Set<Node> closed = new HashSet<>();
Node start = new Node("120345678");
Node goal = new Node("012345678");
open.add(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll();
int pos = current.getData().indexOf('0');
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, pos, open, closed);
down(current, pos, open, closed);
left(current, pos, open, closed);
right(current, pos, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition >= 3) {
char substitutedChar = current.getData().charAt(zeroPosition - 3);
open.add(new Node(current.getData().substring(0, zeroPosition - 3) + '0'
+ current.getData().substring(zeroPosition - 2, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition <= 5) {
char substitutedChar = current.getData().charAt(zeroPosition + 3);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1, zeroPosition + 3) + '0'
+ current.getData().substring(zeroPosition + 4), current));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 0) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition - 1) + '0' + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 2) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar + '0'
+ current.getData().substring(zeroPosition + 2), current));
}
}
private static void printPath(Node current) {
Stack<String> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
Do note that I haven't changed the basic board representation (you chose to use String, while I recommend using a 2d array, where swaps are much less costly and the code becomes easier to understand)
A few notes:
To print the entire "path" you must maintain connections between the "steps" of your solution
Avoid using globals where possible
Prefer using Interfaces (Set, Queue) as the types of your collections (and choose them based on how you would use them)
Java 8 doesn't require you to specify the concrete types used in a generic collection during construction (So use Set<String> set = new HashSet<>(); instead of using Set<String> set = new HashSet<String>();
Where possible, avoid using superfluous (and less readable) conditions / code structure (prefer if (booleanVariable) over if (booleanVariable == true)
(There are probably a few more things to take away from this, but this is a useful list to start with)
EDIT:
a version where data is a 2d array is added below
package basic;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final char[][] data;
public Node getPrevious() {
return previous;
}
public char[][] getData() {
return data;
}
public int getZeroX() {
return zeroX;
}
public int getZeroY() {
return zeroY;
}
private final int zeroX;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(data);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (!Arrays.deepEquals(data, other.data))
return false;
return true;
}
private final int zeroY;
public Node(Node previous, char[][] data, int zeroX, int zeroY) {
super();
this.previous = previous;
this.data = data;
this.zeroX = zeroX;
this.zeroY = zeroY;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>(); //Stack<Node> open = new Stack<>();
Set<Node> closed = new HashSet<>();
Node start = new Node(null, new char[][] { { '1', '2', '0' }, { '3', '4', '5' }, { '6', '7', '8' } }, 2, 0);
Node goal = new Node(null, new char[][] { { '0', '1', '2' }, { '3', '4', '5' }, { '6', '7', '8' } }, 0, 0);
open.add(start); //open.push(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll(); //open.pop();
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, open, closed);
down(current, open, closed);
left(current, open, closed);
right(current, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() - 1][current.getZeroX()];
chars[current.getZeroY() - 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() - 1));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() + 1][current.getZeroX()];
chars[current.getZeroY() + 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() + 1));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() - 1];
chars[current.getZeroY()][current.getZeroX() - 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() - 1, current.getZeroY()));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() + 1];
chars[current.getZeroY()][current.getZeroX() + 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() + 1, current.getZeroY()));
}
}
private static char[][] copy(char[][] data) {
char[][] newData = new char[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
newData[i][j] = data[i][j];
}
}
return newData;
}
private static void printPath(Node current) {
Stack<char[][]> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(char[][] chars) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(chars[i][j]);
}
System.out.println();
}
System.out.println();
}
}
EDIT2: added comments of changes that turn this into DFS
Good luck!
In advance, I apologize for my lack of experience, these are advanced concepts that are difficult to wrap my head around. From what I understand, linear probing is circular, it won't stop until it finds an empty cell.
However I am not sure how to implement it. Some example on how to would be greatly appreciated. Sorry again for the inexperience, I'm not some vetted programmer, I'm picking this up very slowly.
public boolean ContainsElement(V element)
{
for(int i = 0; i < capacity; i++)
{
if(table[i] != null)
{
LinkedList<Entry<K, V>> bucketMethod = table[i];
for(Entry<K, V> entry : bucketMethod)
{
if(entry.getElement().equals(element))
{
return true;
}
}
}
}
return false;
}
Here's a working hash table based on the pseudocode examples found in the Wikipedia article for open addressing.
I think the main differences between the Wikipedia example and mine are:
Treating the hashCode() a little bit due to the way Java does modulo (%) with negative numbers.
Implemented simple resizing logic.
Changed the logic in the remove method a little bit because Java doesn't have goto.
Otherwise, it's more or less just a direct translation.
package mcve;
import java.util.*;
import java.util.stream.*;
public class OAHashTable {
private Entry[] table = new Entry[16]; // Must be >= 4. See findSlot.
private int size = 0;
public int size() {
return size;
}
private int hash(Object key) {
int hashCode = Objects.hashCode(key)
& 0x7F_FF_FF_FF; // <- This is like abs, but it works
// for Integer.MIN_VALUE. We do this
// so that hash(key) % table.length
// is never negative.
return hashCode;
}
private int findSlot(Object key) {
int i = hash(key) % table.length;
// Search until we either find the key, or find an empty slot.
//
// Note: this becomes an infinite loop if the key is not already
// in the table AND every element in the array is occupied.
// With the resizing logic (below), this will only happen
// if the table is smaller than length=4.
while ((table[i] != null) && !Objects.equals(table[i].key, key)) {
i = (i + 1) % table.length;
}
return i;
}
public Object get(Object key) {
int i = findSlot(key);
if (table[i] != null) { // Key is in table.
return table[i].value;
} else { // Key is not in table
return null;
}
}
private boolean tableIsThreeQuartersFull() {
return ((double) size / (double) table.length) >= 0.75;
}
private void resizeTableToTwiceAsLarge() {
Entry[] old = table;
table = new Entry[2 * old.length];
size = 0;
for (Entry e : old) {
if (e != null) {
put(e.key, e.value);
}
}
}
public void put(Object key, Object value) {
int i = findSlot(key);
if (table[i] != null) { // We found our key.
table[i].value = value;
return;
}
if (tableIsThreeQuartersFull()) {
resizeTableToTwiceAsLarge();
i = findSlot(key);
}
table[i] = new Entry(key, value);
++size;
}
public void remove(Object key) {
int i = findSlot(key);
if (table[i] == null) {
return; // Key is not in the table.
}
int j = i;
table[i] = null;
--size;
while (true) {
j = (j + 1) % table.length;
if (table[j] == null) {
break;
}
int k = hash(table[j].key) % table.length;
// Determine if k lies cyclically in (i,j]
// | i.k.j |
// |....j i.k.| or |.k..j i...|
if ( (i<=j) ? ((i<k)&&(k<=j)) : ((i<k)||(k<=j)) ) {
continue;
}
table[i] = table[j];
i = j;
table[i] = null;
}
}
public Stream<Entry> entries() {
return Arrays.stream(table).filter(Objects::nonNull);
}
#Override
public String toString() {
return entries().map(e -> e.key + "=" + e.value)
.collect(Collectors.joining(", ", "{", "}"));
}
public static class Entry {
private Object key;
private Object value;
private Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
public Object getKey() { return key; }
public Object getValue() { return value; }
}
public static void main(String[] args) {
OAHashTable t = new OAHashTable();
t.put("A", 1);
t.put("B", 2);
t.put("C", 3);
System.out.println("size = " + t.size());
System.out.println(t);
t.put("X", 4);
t.put("Y", 5);
t.put("Z", 6);
t.remove("C");
t.remove("B");
t.remove("A");
t.entries().map(e -> e.key)
.map(key -> key + ": " + t.get(key))
.forEach(System.out::println);
}
}
java.util.HashMap implementation of java.util.Map internally provides linear probing that is HashMap can resolve collisions in hash tables.
My code below is supposed to sort version numbers into proper order. For the most part it works, but it fails a hidden test case that I don't have access to. Given that is there any edge case you can see that I might be missing.
import java.util.*;
public class Answer {
public static void main(String[] args)
{
//Testing
String[] versions = {"0.0.0","0","0.0","1.113","0.0.0.1","2.0.0","1.2","2","0.1","1.2.1","1.1.1","2.0"};
String[] results = answer(versions);
for(int i =0; i<results.length;i++)
{
System.out.println(results[i]);
}
}
public static String[] answer(String[] l) {
String temp = new String();
//Insertion sort on the given array to assign correct version numbers
for (int i = 1; i < l.length; i++) {
for(int j = i ; j > 0 ; j--){
if(compareVersion(l[j],l[j-1])<0){
temp = l[j];
l[j] = l[j-1];
l[j-1] = temp;
}
}
}
return l;
}
//Will compare version numbers breaking it apart into a String array
public static int compareVersion(String version1, String version2) {
String[] arr1 = version1.split("\\.");
String[] arr2 = version2.split("\\.");
int i=0;
while(i<arr1.length || i<arr2.length){
if(i<arr1.length && i<arr2.length){
if(Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i])){
return -1;
}else if(Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i])){
return 1;
}
else if(Integer.parseInt(arr1[i]) == Integer.parseInt(arr2[i]))
{
int result = specialCompare(version1,version2);
if(result != 0)
{
return result;
}
}
} else if(i<arr1.length){
if(Integer.parseInt(arr1[i]) != 0){
return 1;
}
} else if(i<arr2.length){
if(Integer.parseInt(arr2[i]) != 0){
return -1;
}
}
i++;
}
return 0;
}
// Meant for when version numbers such as 2 and 2.0 arise. This method will make sure to
// put the smaller version number ( in length) first
public static int specialCompare(String str1, String str2)
{
String[] arr1 = str1.split("\\.");
String[] arr2 = str2.split("\\.");
for(int i =1; i<arr1.length;i++)
{
if(Integer.parseInt(arr1[i]) != 0)
{
return 0;
}
}
for(int j =1; j<arr2.length;j++)
{
if(Integer.parseInt(arr2[j]) != 0)
{
return 0;
}
}
if(arr1.length < arr2.length)
{
return -1;
}
else
{
return 1;
}
}
}
I read Lukas Eder's blog post in the comment above and created a java.util.Comparator which orders by version (or chapter) number, based on a JDK proposal.
VersionNumberComparator is defined in a GitHub gist. The follow code shows how it works.
import java.util.ArrayList;
import java.util.List;
public class JavaTest {
public static void main(String[] args) {
final List<String> chapters = new ArrayList<>();
chapters.add("1.1");
chapters.add("1.2");
chapters.add("1");
chapters.add("1.3");
chapters.add("1.1.1");
chapters.add("5.6");
chapters.add("1.1.10");
chapters.add("4");
chapters.add("1.1.9");
chapters.add("1.2.1.10");
chapters.add("2.1.1.4.5");
chapters.add("1.2.1.9");
chapters.add("1.2.1");
chapters.add("2.2.2");
chapters.add("1.2.1.11");
System.out.println("UNSORTED: " + chapters.toString());
chapters.sort(VersionNumberComparator.getInstance());
System.out.println("SORTED: " + chapters.toString());
}
}
Produces the following output:
UNSORTED: [1.1, 1.2, 1, 1.3, 1.1.1, 5.6, 1.1.10, 4, 1.1.9, 1.2.1.10, 2.1.1.4.5, 1.2.1.9, 1.2.1, 2.2.2, 1.2.1.11]
SORTED: [1, 1.1, 1.1.1, 1.1.9, 1.1.10, 1.2, 1.2.1, 1.2.1.9, 1.2.1.10, 1.2.1.11, 1.3, 2.1.1.4.5, 2.2.2, 4, 5.6]
I have recently had a need to do this in a more generic way for arbitrary file names, similar to how Windows Explorer sorts files:
I wrote a blog post about this. The idea was inspired by this answer here. The comparator used for ordering files this way looks like this:
public final class FilenameComparator implements Comparator<String> {
private static final Pattern NUMBERS =
Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
#Override
public final int compare(String o1, String o2) {
// Optional "NULLS LAST" semantics:
if (o1 == null || o2 == null)
return o1 == null ? o2 == null ? 0 : -1 : 1;
// Splitting both input strings by the above patterns
String[] split1 = NUMBERS.split(o1);
String[] split2 = NUMBERS.split(o2);
for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
char c1 = split1[i].charAt(0);
char c2 = split2[i].charAt(0);
int cmp = 0;
// If both segments start with a digit, sort them numerically using
// BigInteger to stay safe
if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9')
cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));
// If we haven't sorted numerically before, or if numeric sorting yielded
// equality (e.g 007 and 7) then sort lexicographically
if (cmp == 0)
cmp = split1[i].compareTo(split2[i]);
// Abort once some prefix has unequal ordering
if (cmp != 0)
return cmp;
}
// If we reach this, then both strings have equally ordered prefixes, but
// maybe one string is longer than the other (i.e. has more segments)
return split1.length - split2.length;
}
}
If you want to sort some versions (e.g. 0.4.3, 5.3.5, 1.2.4) you could use my approach which includes using a java.util.Comparator. To use this you have to use a sorting method (e.g. Arrays.sort(new String[] {"0.4.3", "5.3.5", "1.2.4"}, new VersionComparator())). The VersionComparator class is written below:
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public final class VersionComparator implements Comparator<String> {
#Override
public int compare(String version1, String version2) {
if (checkVersionFormat(version1) == false || checkVersionFormat(version2) == false) {
System.out.println("One of the given versions uses a false format");
}
List<String> firstVersionElements = Arrays.asList(version1.split("\\."));
List<String> secondVersionElements = Arrays.asList(version2.split("\\."));
int maxVersionElements = getMaxNumber(firstVersionElements.size(), secondVersionElements.size(), 0);
for (int counter = 0; counter < maxVersionElements; counter++) {
if (firstVersionElements.size() == counter && secondVersionElements.size() == counter) {
return 0;
}
if (firstVersionElements.size() == counter) {
return 1;
}
if (secondVersionElements.size() == counter) {
return -1;
}
int firstIntElement = Integer.valueOf(firstVersionElements.get(counter));
int secondIntElement = Integer.valueOf(secondVersionElements.get(counter));
if (firstIntElement < secondIntElement) {
return 1;
}
if (firstIntElement > secondIntElement) {
return -1;
}
}
return 0;
}
private boolean checkVersionFormat(String version) {
String versionCopy = new String(version);
String[] validChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "." };
for (String character : validChars) {
versionCopy = versionCopy.replace(character, "");
}
return versionCopy.equals("");
}
public static int getMaxNumber(Integer... ints) {
int maximumInt = ints[0];
for (int processInt : ints) {
if (processInt > maximumInt) {
maximumInt = processInt;
}
}
return maximumInt;
}
}
From your comments in your code above the specialCompare method…
Meant for when version numbers such as 2 and 2.0 arise. This method
will make sure to put the smaller version number (in length) first
So I am guessing from this that you want the version to be sorted by the length of the version number. Example: from your supplied versions string array you want to sort as below…
0
2
0.0
0.1
1.2
1.113
2.0
0.0.0
1.1.1
1.2.1
2.0.0
0.0.0.1
If this is the case, then you seem to be making this more complicated than it has to be. When you get two versions where the version lengths differ, then the one with the shorter version length should go first. So a simple check on the length of the version split arrays should solve this. If they are the same length, then you need to check each version. There is no need for a specialCompare method when the version lengths are the same. Simply check each version and if they are the same, then go to the next version number and so on. As soon as one version is different then you will know what to return. If you go through the whole array then you know all the version numbers are the same.
Below is a change to the compareVersion method using the logic above. There is no need for a specialCompare method. I am guessing this is what you are looking for.
public static int compareVersion(String version1, String version2)
{
String[] arr1 = version1.split("\\.");
String[] arr2 = version2.split("\\.");
if (arr1.length < arr2.length)
return -1;
if (arr1.length > arr2.length)
return 1;
// same number of version "." dots
for (int i = 0; i < arr1.length; i++)
{
if(Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i]))
return -1;
if(Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i]))
return 1;
}
// went through all version numbers and they are all the same
return 0;
}
package com.e;
import java.util.*;
/**
* Created by dpc on 17-2-27.
*
*/
public class VersionComparator implements Comparator {
#Override
public int compare(String o1, String o2) {
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null && o2 != null) {
return -1;
} else if (o1 != null && o2 == null) {
return 1;
} else {
if (o1.length() == 0 && o2.length() == 0) {
return 0;
} else if (o1.length() == 0 && o2.length() > 0) {
return -1;
} else if (o1.length() > 0 && o2.length() == 0) {
return 1;
} else {
return compareVersion(o1, o2);
}
}
}
public static int compareVersion(String version1, String version2) {
String[] arr1 = version1.split("\\.");
String[] arr2 = version2.split("\\.");
try {
int i = 0;
while (i < arr1.length || i < arr2.length) {
if (i < arr1.length && i < arr2.length) {
if (Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i])) {
return -1;
} else if (Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i])) {
return 1;
} else if (Integer.parseInt(arr1[i]) == Integer.parseInt(arr2[i])) {
int result = specialCompare(version1, version2);
if (result != 0) {
return result;
}
}
} else if (i < arr1.length) {
if (Integer.parseInt(arr1[i]) != 0) {
return 1;
}
} else if (i < arr2.length) {
if (Integer.parseInt(arr2[i]) != 0) {
return -1;
}
}
i++;
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public static int specialCompare(String str1, String str2) {
String[] arr1 = str1.split("\\.");
String[] arr2 = str2.split("\\.");
for (int i = 1; i < arr1.length; i++) {
if (Integer.parseInt(arr1[i]) != 0) {
return 0;
}
}
for (int j = 1; j < arr2.length; j++) {
if (Integer.parseInt(arr2[j]) != 0) {
return 0;
}
}
if (arr1.length < arr2.length) {
return -1;
} else {
return 1;
}
}
// test
public static List<String> getLowerList(String str, Comparator<String> comparator, List<String> list) {
if (str == null) {
return list;
}
List<String> newlist = new ArrayList<String>();
newlist.add(str);
newlist.addAll(list);
// sort
Collections.sort(newlist, comparator);
// search
int endIndex = Collections.binarySearch(newlist, str);
if (endIndex >= 0) {
// sublist 0 1
return newlist.subList(0, endIndex + 1);
} else {
return new ArrayList<String>();
}
}
public static void main(String[] args) {
List<String> test1 = Arrays.asList(new String[]{
"2.1.1", "1.21.22", "1.21.25", "1.113", "0.0.0.1",
"2.0.0", "1.2", "2.0", "0.1", "1.2.1", "1.1.1",
"11", "100", "" + Integer.MAX_VALUE + ".1", "",
"2.0", "10.1"});
List<String> test2 = Arrays.asList(new String[]{"", null, "0", "10.20.100", "3.1.1", "9.8", "10.3.92"});
List<String> newlist = new ArrayList<String>();
newlist.addAll(test1);
newlist.addAll(test2);
Collections.sort(newlist, new VersionComparator());
VersionComparator compareVersion = new VersionComparator();
System.out.println(newlist);
System.out.println(getLowerList("2", compareVersion, newlist));
System.out.println(getLowerList("3", compareVersion, newlist));
System.out.println(getLowerList("4", compareVersion, newlist));
System.out.println(getLowerList("5", compareVersion, newlist));
}
}
I came across a post showing how to arrange char array by alphabet order.
seeing this can be done, I want to output the alphabetical order of each character of the input string, in order of the characters of the input string.
I'm a bit stuck. I can get the string reordered alphabetically, but I don't know what to do next.
example is 'monkey' to '354216'
because 'ekmnoy' e is alphabetically first from the set of given characters so e = 1 , k is the second alpha char when sorted so k = 2, and so on.
if you cannot understand I can provide more example to make things clear out.
Code
String str = "airport";
Character[] chars = new Character[str.length()];
for (int z = 0; z < chars.length; z++) {
chars[z] = str.charAt(z);
}
Arrays.sort(chars, new Comparator<Character>() {
public int compare(Character c1, Character c2) {
int cmp = Character.compare(
Character.toLowerCase(c1.charValue()),
Character.toLowerCase(c2.charValue()));
if (cmp != 0) {
return cmp;
}
return Character.compare(c1.charValue(), c2.charValue());
}
});
StringBuilder sb = new StringBuilder(chars.length);
for (char c : chars) {
sb.append(c);
}
str = sb.toString();
System.out.println(sb);
Output
aioprrt
expected output
Orange -> aegnOr
561432 - 123456
Monkey -> ekMnoy
354216 -> 123456
I dont know what you want to do with double characters, but if you add this few lines to your code at the end you are getting the right result. Iterate over the sorted String and replace the charakters in the original String with their indices in the sorted String.
String originalStr = "airport";
for(int i = 0; i<str.length(); i++) {
originalStr = originalStr.replace(str.charAt(i), String.valueOf(i+1).charAt(0));
}
System.out.println(originalStr);
Output: 1254357
If you want to get the output: 1254367 use replaceFirst:
originalStr = originalStr.replaceFirst(String.valueOf(str.charAt(i)), String.valueOf(i+1));
Input:Orange
Output:561432
Input:Monkey
Output:354216
The whole code:
String str = "airport";
String originalStr = str; //creat a backup of str because you change it in your code
Character[] chars = str.toCharArray();
Arrays.sort(chars, new Comparator<Character>() {
public int compare(Character c1, Character c2) {
int cmp = Character.compare(
Character.toLowerCase(c1.charValue()),
Character.toLowerCase(c2.charValue()));
if (cmp != 0) {
return cmp;
}
return Character.compare(c1.charValue(), c2.charValue());
}
});
str = String.valueOf(chars);
System.out.println(str);
//Iterate over the sorted String and replace the charakters in the original String with their indices in the sorted String
for(int i = 0; i<str.length(); i++) {
originalStr = originalStr.replaceFirst(String.valueOf(str.charAt(i)), String.valueOf(i+1));
}
System.out.println(originalStr);
Once you have arranged the characters in order (in a different array from the original) then create a third array by walking the original string and choosing the index of each character from te sorted string.
input: edcba
sorted: abcde
index: 01234
Pseudocode...
for( int i = 0; i < input.length(); i++ ) {
index[i] = sorted.indexOf(input[i]);
}
Result should be 43210 with the given input.
Note that strings with more than 10 characters will result in ambiguous output, which can be handled by inserting spaces in the output. Example:
abcdefghijk ->
012345678910
You can use this below code:
package Test;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class Arrange {
public static void main(String[] args) {
String str = "money";
List<Test> strs=new LinkedList<Test>();
List<Test> final_result=new LinkedList<Test>();
for(int i=0;i<str.length();i++)
{
Test t=new Test(i, ""+str.charAt(i), 0);
strs.add(t);
}
Collections.sort(strs,new Comparator<Test>() {
#Override
public int compare(Test o1, Test o2) {
return (o1.getS().compareToIgnoreCase(o2.getS()));
}
});
Integer i=1;
for (Test st : strs) {
st.setJ(i);
final_result.add(st);
i++;
}
Collections.sort(final_result,new Comparator<Test>() {
#Override
public int compare(Test o1, Test o2) {
return (o1.getI().compareTo(o2.getI()));
}
});
for (Test test : final_result) {
System.out.println(test.getJ());
}
}
}
class Test{
private Integer i;
private String s;
private Integer j;
public Test() {
// TODO Auto-generated constructor stub
}
public Test(Integer i, String s, Integer j) {
super();
this.i = i;
this.s = s;
this.j = j;
}
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public Integer getJ() {
return j;
}
public void setJ(Integer j) {
this.j = j;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((i == null) ? 0 : i.hashCode());
result = prime * result + ((j == null) ? 0 : j.hashCode());
result = prime * result + ((s == null) ? 0 : s.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (i == null) {
if (other.i != null)
return false;
} else if (!i.equals(other.i))
return false;
if (j == null) {
if (other.j != null)
return false;
} else if (!j.equals(other.j))
return false;
if (s == null) {
if (other.s != null)
return false;
} else if (!s.equals(other.s))
return false;
return true;
}
}
Question 4:
Given an integer array, convert it into a linked list with each node containing one sequence.
Sample Input : [1, 3, 4, 5, 8, 9, 11, 13, 14, 15, 16, 20, 23, 30,31,32]
Sample Linked List : [1] -> [3,4,5] -> [8,9] -> [11] -> [13,14,15,16]->[20]->[23]->[30,31,32]
The question may seems to be easy but it's bit difficult to answer.Can anyone write code for the above in Java without using Collection or LinkedList ?
Below is the code for detecting sequence (which might help).
class Sequence {
public static String detectSequence(int seq[]) {
String result = "";
for (int i = 0; i < seq.length - 1; i++) {
if (seq[i + 1] == seq[i] + 1) {
result += seq[i] + " ";
if (i != seq.length - 2) {
if (seq[i + 1] != seq[i + 2] - 1) {
result += seq[i + 1];
}
}
} else {
result += " ";
}
}
if (seq[seq.length - 1] == seq[seq.length - 2] + 1) {
result += seq[seq.length - 1];
}
return result;
}
}
class Question1 {
public static void main(String[] cla) {
int seqArray[] = {
4, 1, 2, 3, 4, 5, 8, 4, 7, 4, 5, 6, 7, 7, 7, 7, 7, 10, 11, 13, 1, 2, 3, 4
};
String res = Sequence.detectSequence(seqArray);
System.out.println(res);
}
}
just to give you a start...
public YourLinkedList splitToSequences(int[] array) {
YourLinkedList list = new YourLinkedList();
if(array.length > 0) {
YourSequence sequence = new YourSequence();
int currentNumber;
int lastNumber = array[0];
sequence.add(lastNumber);
for(int index = 1; index < array.length; index++) {
currentNumber = array[index];
if(currentNumber != lastNumber + 1) { // curentNumber breaks the sequence
list.add(sequence); // save the old sequence to list
sequence = new YourSequence(); // and start a new one
}
sequence.add(currentNumber);
}
list.add(sequence);
}
return list;
}
Now go and figure out your linked list and sequence classes and do the printing stuff...
A minimalistic implementation of a linked list
public class MyLinkedList<T1> {
private MyLinkedListItem<T1> first = null;
private MyLinkedListItem<T1> last = null;
public MyLinkedList() {
}
public void add(T1 item) {
MyLinkedListItem<T1> newItem = new MyLinkedListItem<T1>(item);
if (first == null) {
first = newItem;
} else {
last.setNext(newItem);
}
last = newItem;
}
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
if(first != null) {
MyLinkedListItem<T1> current = first;
while(current.hasNext()) {
buffer.append(current.toString());
buffer.append(" -> ");
current = current.getNext();
}
buffer.append(current.toString());
}
return buffer.toString();
}
private class MyLinkedListItem<T2> {
private T2 data;
private MyLinkedListItem<T2> next = null;
public MyLinkedListItem(T2 data) {
this.data = data;
}
public boolean hasNext() {
return next != null;
}
public MyLinkedListItem<T2> getNext() {
return next;
}
public void setNext(MyLinkedListItem<T2> next) {
this.next = next;
}
#Override
public String toString() {
return data.toString();
}
}
}
First the code that splits the array in several chunks can be written using an Iterator to avoid to mix this algorithm with the code that creates the linked list.
Then there is a way to implement a simple linked list in a functional fashion (so the whole list is immutable).
Obviously, this code is unreadable but fun !
import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.IntStream;
public class LinkedConsecutiveInts {
private static Iterator<int[]> iterator(int[] array) {
return new Iterator<int[]>() {
private int index;
#Override
public boolean hasNext() {
return index < array.length;
}
#Override
public int[] next() {
int first = array[index];
int value = first + 1;
int i = 1;
for(; index + i < array.length && array[index + i] == value++; i++) {
// empty
}
index += i;
return IntStream.range(first, first + i).toArray();
}
};
}
interface Seq<T> {
void forEach(Consumer<? super T> consumer);
default <U> Seq<U> map(Function<? super T, ? extends U> mapper) {
return consumer -> forEach(e -> consumer.accept(mapper.apply(e)));
}
default String joining(String separator) {
StringBuilder builder = new StringBuilder();
forEach(e -> builder.append(e).append(separator));
if (builder.length() != 0) {
builder.setLength(builder.length() - separator.length());
}
return builder.toString();
}
static <T> Seq<T> from(Iterator<? extends T> it) {
if (!it.hasNext()) {
return consumer -> { /* empty */ };
}
T element = it.next();
Seq<T> next = from(it);
return consumer -> { consumer.accept(element); next.forEach(consumer); };
}
}
public static void main(String[] args) {
int[] values = { 1, 3, 4, 5, 8, 9, 11, 13, 14, 15, 16, 20, 23, 30, 31, 32 };
Seq<int[]> seq = Seq.from(iterator(values));
System.out.println(seq.map(Arrays::toString).joining(" -> "));
}
}