If I have a 2D array that is arranged as follows :
String X[][] = new String [][] {{"127.0.0.9", "60", "75000","UDP", "Good"},
{"127.0.0.8", "75", "75000","TCP", "Bad"},
{"127.0.0.9", "75", "70000","UDP", "G开发者_如何学运维ood"},
{"127.0.0.1", "", "70000","UDP", "Good"},
{"127.0.0.1", "75", "75000","TCP", "Bad"}
};
I want to know the frequency of each value .. so I27.0.0.9 gets 2. How can I do a general solution for this ? In Java or any algorithm for any language ?
It looks like you need a custom data type to encapsulate each row rather than using a String[][]
, but to answer your question more directly, you can use a Map<String,Integer>
for each column. A HashMap<String,Integer>
can be expected to do this in optimal time.
Here's a snippet to demonstrate the idea:
import java.util.*;
public class Frequency {
static void increment(Map<String,Integer> map, String key) {
Integer count = map.get(key);
map.put(key, (count == null ? 0 : count) + 1);
}
public static void main(String[] args) {
String table[][] = new String[][] {
{"127.0.0.9", "60", "75000","UDP", "Good"},
{"127.0.0.8", "75", "75000","TCP", "Bad"},
{"127.0.0.9", "75", "70000","UDP", "Good"},
{"127.0.0.1", "", "70000","UDP", "Good"},
{"127.0.0.1", "75", "75000","TCP", "Bad"}
};
final int M = table.length;
final int N = table[0].length;
List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
for (int i = 0; i < N; i++) {
maps.add(new HashMap<String,Integer>());
}
for (String[] row : table) {
for (int i = 0; i < N; i++) {
increment(maps.get(i), row[i]);
}
}
for (Map<String,Integer> map : maps) {
System.out.println(map);
}
System.out.println(maps.get(0).get("127.0.0.9"));
}
}
This produces the following output: each line is a frequency map for each column:
{127.0.0.9=2, 127.0.0.8=1, 127.0.0.1=2}
{=1, 60=1, 75=3}
{75000=3, 70000=2}
{UDP=3, TCP=2}
{Good=3, Bad=2}
2
Note: if you don't care about mixing values from all columns together, then you only need one Map
, instead of a List<Map>
one for each column. This would make the design even worse, though. You really should encapsulate each row into a custom type, instead of a having everything mixed as String[][]
.
For example some of those columns really looks like they should be an enum
.
enum Protocol { UDP, TCP; }
enum Condition { Good, Bad; }
//...
You can use Map for Java as above question, use Dictionary for C# The general algorithm is that you have a table/ array of key - value. And you can give the datastructure a key, it will find for you the correct value for that key
Don't store everything as Strings. This slows down processing and is not elegant. Why store a port number (which is an int) as a string? or a boolean value "good" "bad" as a string? Create a custom class that have fields with types corresponding to their semantic.
// I think this is an example of what Vodkhang is describing
public static void main(String[] args){
String X[][] = new String [][] {{"127.0.0.9", "60", "75000","UDP", "Good"},
{"127.0.0.8", "75", "75000","TCP", "Bad"},
{"127.0.0.9", "75", "70000","UDP", "Good"},
{"127.0.0.1", "", "70000","UDP", "Good"},
{"127.0.0.1", "75", "75000","TCP", "Bad"}
};
final int M = X.length;
final int N = X[0].length;
HashMap<Object, ArrayList> map = new HashMap();
for(int i = 0; i < M; i++){
for(int j = 0; j < M; j++){
String s = X[i][j];
if( map.containsKey(s) ){
// add the string to the existing array list
ArrayList al = map.get(s);
al.add(s);
map.put(s,al);
} else {
// make a new node
ArrayList al = new ArrayList();
al.add(s);
map.put(s, al);
}
}
}
// now loop through each pair in the map
// for each arraylist print out the size
Set<Object> set = map.keySet();
for(Object s: set){
ArrayList al = map.get(s);
System.out.println(s.toString() + " " + al.size() );
}
}
精彩评论