Method to Iterate over a Google Guava [duplicate] - guava

I create and populate a Guava Table using the following code:
Table<String, String, Integer> table = HashBasedTable.create();
table.put("A", "B", 1);
table.put("A", "C", 2);
table.put("B", "D", 3);
I wonder how to iterate over table and print out both keys and value for each row? So, the desired output is:
A B 1
A C 2
B D 3

Im not Guava user so this may be overkill (if it is true then will be glad for any info) but you can use table.rowMap() to get Map<String, Map<String, Integer>> which will represents data in table in form {A={B=1, C=2}, B={D=3}}. Then just iterate over this map like:
Map<String, Map<String, Integer>> map = table.rowMap();
for (String row : map.keySet()) {
Map<String, Integer> tmp = map.get(row);
for (Map.Entry<String, Integer> pair : tmp.entrySet()) {
System.out.println(row+" "+pair.getKey()+" "+pair.getValue());
}
}
or
for (Map.Entry<String, Map<String,Integer>> outer : map.entrySet()) {
for (Map.Entry<String, Integer> inner : outer.getValue().entrySet()) {
System.out.println(outer.getKey()+" "+inner.getKey()+" "+inner.getValue());
}
}
or even better using com.google.common.collect.Table.Cell
for (Cell<String, String, Integer> cell: table.cellSet()){
System.out.println(cell.getRowKey()+" "+cell.getColumnKey()+" "+cell.getValue());
}

you can use :
System.out.println(Arrays.asList(table));
and the output will be
[{A={B=1, C=2}, B={D=3}}]

Related

How to print out a Hash table in Matlab?

I have a code, in which a Hashtable is created using java.util.Hashtable();
Now, I'm gonna know how to see the content of that table, i.e. how to print out that Hashtable?
Iterate means to loop through, to go through one by one in a collection.
Here is a code example.
import java.util.Hashtable;
import java.util.Map.Entry;
public class IterateHashtable {
public static void main(String[] args) {
// creating myHash object
Hashtable<String, String> myHash = new Hashtable<String, String>();
// adding key-value pairs to myHash
myHash.put("Apple", "Red");
myHash.put("Banana", "Yellow");
myHash.put("Guava", "Green");
// Get entrySet() and Iterate using for-each loop
for(Map.Entry<String, String> entry1 : myHash.entrySet()) {
System.out.println("Fruit : " + entry1.getKey() + " Color : " + entry1.getValue());
}
}
}

Getting multiple data from Firestore

Above is my database in Firestore. As can be seen, there are 2 Strings and 2 (or more) Arrays as fields.
I will be fetching the data to convert the same into different graphs
For ex: 1. Graph showing sum of all chapters of all users
2. Graph showing sum of "chapter1" of all users.
3. Graph showing averages of all chapters etc.,
These graphs will be in different activities based on the selection of the user and the calculations are done specific to that activity.
Now my issue is in accessing this data to use it in various activities.
I have tried the HashMap Map> to store phonenumb, chapter(x), and values of chapter(x) respectively.
Below is the code to access the data:
CollectionReference chemistry = db.collection("RESULTS").document("Summary").collection("ChemistryVII");
chemistry
.whereEqualTo("school", "Test School")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (DocumentSnapshot document : task.getResult()) {
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().contains("chapter")) {
if (outer.isEmpty() || !outer.containsKey(map.get("phonenumb"))) {
Map<String, Object> inner = new HashMap<>();
inner.put(entry.getKey(), entry.getValue());
String phonenumb = map.get("phonenumb").toString();
outer.put(phonenumb, inner);
} else {
Map<String, Object> inner = new HashMap<>();
inner.put(entry.getKey(), entry.getValue());
String phonenumb = map.get("phonenumb").toString();
outer.put(phonenumb, inner);
}
}
}
}
//Toast("Outer Details " + outer);
schoolGraph();
}
});
However, this will not work as there could be multiple entries for the given key (phonenumb).
Trying to understand the best way to access such data and use it for multiple activities.
Hash map key is unique. Every time you add a new Object with the same key, the old valude with the same key will be overwritten.
I think the logic in this part is correct:
if (outer.isEmpty() || !outer.containsKey(map.get("phonenumb"))) {
Map<String, Object> inner = new HashMap<>();
inner.put(entry.getKey(), entry.getValue());
String phonenumb = map.get("phonenumb").toString();
outer.put(phonenumb, inner);
You insert in the inner map the first chapter sum. Because the outer map does not have the key phonenumb, you need to insert in the outer map too.
However in the else part:
Map<String, Object> inner = new HashMap<>();
inner.put(entry.getKey(), entry.getValue());
String phonenumb = map.get("phonenumb").toString();
outer.put(phonenumb, inner);
You do not need the outer.put(phonenumb, inner);, because inner exists already and has the sum of a chapter.
Here the outer has the key 'phonenumber', you just have to insert to the inner map the new entry sum: inner[chapter] = sum .
You need something like outert[phonenumb][chapter] = sum

How to map input KStream <String,String> into <String, CarClass> using KeyValueMapper?

Receiving the Json data which i simply want to map on CarClass and want to create new stream but map method doesn't allow me it to map on custom datatype
The method map(KeyValueMapper>) in the type KStream is not applicable for the arguments (new KeyValueMapper>(){})?
From http://docs.confluent.io/current/streams/developer-guide.html#stateless-transformations:
The example changes the value type from byte[] to Integer. For String to CarClass is would be the same.
KStream<byte[], String> stream = ...;
// Java 8+ example, using lambda expressions
// Note how we change the key and the key type (similar to `selectKey`)
// as well as the value and the value type.
KStream<String, Integer> transformed = stream.map(
(key, value) -> KeyValue.pair(value.toLowerCase(), value.length()));
// Java 7 example
KStream<String, Integer> transformed = stream.map(
new KeyValueMapper<byte[], String, KeyValue<String, Integer>>() {
#Override
public KeyValue<String, Integer> apply(byte[] key, String value) {
return new KeyValue<>(value.toLowerCase(), value.length());
}
});
However, if you want to only modify the value, I would recommend to use mapValues() instead of map().

Returning PostgreSQL aggregations to a HashMap using MyBatis

I have a super simple table test e.g.
create table test (
id serial primary key,
status varchar (10)
);
insert into test (status)
values ('ready'), ('ready'),
('steady'),
('go'), ('go'), ('go'),
('new');
To get the aggregated counts I can run: -
1) Simple multi-row result using group by
select status,
count(id) as count
from test
group by status
... which returns ...
-------+-------
status | counts
-------+-------
go | 3
ready | 2
new | 1
steady | 1
-------+-------
2) Single-Row Result using jsonb_object_agg
with stats as (
select status,
count(id) as count
from test
group by status
)
select jsonb_object_agg (status, count) as status_counts from stats
... which returns ...
--------------------------------------------------
status_counts
--------------------------------------------------
{ "go" : 3, "new" : 1, "ready" : 2, "steady" : 1 }
--------------------------------------------------
Mybatis Interface method.
In my Java code (via MyBatis) I have a method: -
public Map<String, Integer> selectStatusCounts();
What I'm keen to figure out is how to map either query to the Map<String, Integer> Java object via MyBatis?
Update (1)
On a_horse_with_no_name advice and this stackover article I've come up with this: -
3) Single-Row Result using hstore
select hstore(array_agg(hs_key), array_agg(hs_value::text))
from (
select
status,
count(id) as count
from test
group by status
) x(hs_key,hs_value)
... which returns ...
--------------------------------------------------
status_counts
--------------------------------------------------
"go"=>"3", "new"=>"1", "ready"=>"2", "steady"=>"1"
--------------------------------------------------
Using something like this could maybe work: -
https://github.com/gbif/checklistbank/blob/master/checklistbank-mybatis-service/src/main/java/org/gbif/checklistbank/service/mybatis/postgres/HstoreCountTypeHandler.java
Will test now! :-)
Update (2)
Thanks a_horse_with_no_name again for your contributions - I'm very close now but still weirdness with MyBatis. Here is a type handler I created (so I can reuse the aggregations elsewhere): -
#MappedTypes(LinkedHashMap.class)
#MappedJdbcTypes(JdbcType.OTHER)
public class MyBatisMapHstoreToStringIntegerMap implements TypeHandler<Map<String, Integer>> {
public MyBatisMapHstoreToStringIntegerMap() {}
public void setParameter(PreparedStatement ps, int i, Map<String, Integer> map, JdbcType jdbcType) throws SQLException {
ps.setString(i, HStoreConverter.toString(map));
}
public Map<String, Integer> getResult(ResultSet rs, String columnName) throws SQLException {
return readMap(rs.getString(columnName));
}
public Map<String, Integer> getResult(ResultSet rs, int columnIndex) throws SQLException {
return readMap(rs.getString(columnIndex));
}
public Map<String, Integer> getResult(CallableStatement cs, int columnIndex) throws SQLException {
return readMap(cs.getString(columnIndex));
}
private Map<String, Integer> readMap(String hstring) throws SQLException {
if (hstring != null) {
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
Map<String, String> rawMap = HStoreConverter.fromString(hstring);
for (Map.Entry<String, String> entry : rawMap.entrySet()) {
map.put(entry.getKey(), Integer.parseInt(entry.getValue())); // convert from <String, String> to <String,Integer>
}
return map;
}
return null;
}
}
... and here's the mapper interface ...
public interface TestMapper {
public Map<String, Integer> selectStatusCounts();
}
... and here is the <select> inside the XML mapper file ...
<select id="selectStatusCounts" resultType="java.util.LinkedHashMap">
select hstore(array_agg(hs_key), array_agg(hs_value::text)) as status_counts
from (
select
status,
count(id) as count
from test
group by status
) x(hs_key,hs_value)
</select>
However, it returns a Map with one entry called status_counts the value of which is the actual map I want i.e. {status_counts={new=1, ready=2, go=3, steady=1}}
The following is my maven dependencies with regards PostgreSQL / MyBatis: -
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
The easiest way is to define a hstore_agg() function:
CREATE AGGREGATE hstore_agg(hstore)
(
SFUNC = hs_concat(hstore, hstore),
STYPE = hstore
);
Then you can do this:
select hstore_agg(hstore(status, cnt::text))
from (
select status, count(*) cnt
from test
group by status
) t;
With the current JDBC driver Statement.getObject() will return a Map<String, String>.
As hstore only stores strings, it can't return a Map<String, Integer>
Posting an answer (which isn't perfect) but keen to see if anyone else has a better solution.
My answer is based on this stackoverflow answer: -
Return HashMap in mybatis and use it as ModelAttribute in spring MVC
I've created a POJO class called KeyValue: -
public class KeyValue<K, V> {
private K key;
private V value;
public KeyValue() {
}
public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
... and changed the test mapper method to ...
#MapKey("key")
public Map<String, KeyValue<String, Integer>> selectStatusCounts();
Note use of #MapKey parameter
I'm using the "1) Simple multi-row result using group by" SQL from original question and changed the result columns to key + value (so it maps to the new KeyValue object) as follows: -
<select id="selectStatusCounts" resultType="test.KeyValue">
select status as key,
count(id) as value
from bulk_upload
group by status
</select>
Accessing this in Java is achieved as follows: -
Map<String, KeyValue<String, Integer>> statusCounts = mapper.selectStatusCounts();
And to retrieve e.g. the value from map of new items we simply do: -
int numberOfstatusCounts = statusCounts.get("new").getValue();
I'm fairly happy with this solution but I would still prefer a Map<String, Integer> as opposed to a Map<String, KeyValue<String, Integer>> so not going to accept my solution - it's here purely just to show how I've got something working (for now).

GWT Celltable with data in map

I have my datas as a Map<Key,ArrayList<Value>> So i want my col1 to represent my key and the other columns to represent data in my values. And this Value can be or multiple rows. So i was thinking of putting a celltable inside a celltable but then it will affect my headers(since the number of columns for the outer celltable will be just 2) and also the sorting.
And also if i pass the map directly to ListDataProvider it assumes the number of rows is the number of rows of the map but it is not the case.
So what is the best way to do this ?
I'd suggest using a class RowObject like this:
class RowObject {
private final Key key;
private final Value value;
RowObject(Key key, Value value) {
this.key = key;
this.value = value;
}
/* Getters omitted */
}
Then convert the map to a list of RowObjects and feed the list to the data provider:
List<RowObject> rowObjects = new ArrayList<RowObject>();
for (Entry<Key, ArrayList<Value>> entry : map.entrySet()) {
for (Value value : entry.getValue()) {
rowObjects.add(new RowObject(entry.getKey(), value));
}
}
ListDataProvider<RowObject> dataProvider = new ListDataProvider<RowObject>();
dataProvider.addDataDisplay(cellTable);
dataProvider.setList(rowObjects);
Add columns like this:
Column column = new Column<RowObject, String>(new TextCell()) {
#Override
public String getValue(RowObject object) {
return getStringValueFor(object);
}
};
cellTable.addColumn(column);