for (String varValue : arrayList1) {
Map<String, String> mapInstance = new HashMap<>();
val.put(KEY, VALUE);
val.put(VAR_KEY, varValue);
arrayList2.add(mapInstance);
}
Basically, I want to create a map with two entries and then add each of these maps to a list.
Final list:
{KEY,VALUE} {VAR_KEY,arrayList1.get(0)}
{KEY,VALUE} {VAR_KEY,arrayList1.get(1)}
{KEY,VALUE} {VAR_KEY,arrayList1.get(2)}
...
and so on
It seems you only need a simple map stage.
List<Map<String, String>> list = arrayList1.stream().map(t -> {
Map<String, String> map = new HashMap<>();
map.put("KEY", "VALUE");
map.put("VAR_KEY", t);
return map;
}).collect(Collectors.toList());
What is KEY and VAR_KEY? are they instance variable of some object which you are trying to put in Map from the incoming object.
However, you can try something like this :
Map result =
arrayList1.stream().collect(Collectors.toMap(Class::getKey, c -> c));
Related
Porting an App from Swift to Flutter. In my App, I have a class, MyClass, and am dealing with a list of about 250 instances. At various times, I need to group the objects based on a particular property.
In Swift, I was able to create a grouped list of my objects like so:
var groupedList = Dictionary<String, Array<MyClass>>()
I was then able to loop through my list of objects, and assign items to the right Array as necessary. I thought it might work to make a Map of Lists in Flutter like this:
Map groupedList = Map<String, List<MyClass>>();
Then I could loop through the items, test the property, create a Map entry for each unique value and append the item to the correct List:
for (var item in listOfObjects) {
if (!groupedList.containsKey(item.someproperty)) {
List<MyClass> sublist = [];
groupedList[item.someproperty] = sublist;
}
groupedList[item.someproperty].add(item);
}
What I get, however, is a Map with all the correct Keys, but each List contains only one instance of MyClass, rather than an actual List of MyClasses.
There's a more succinct syntax using putIfAbsent. This gives the results you expect:
void main() {
var groupedList = <String, List<MyClass>>{};
var listOfObjects = <MyClass>[
MyClass('Europe', 'France'),
MyClass('Europe', 'Germany'),
MyClass('Europe', 'Italy'),
MyClass('North America', 'USA'),
MyClass('Asia', 'Japan'),
MyClass('Asia', 'China'),
];
for (var item in listOfObjects) {
groupedList.putIfAbsent(item.someProperty, () => <MyClass>[]).add(item);
}
print(groupedList);
}
class MyClass {
String someProperty;
String someValue;
MyClass(this.someProperty, this.someValue);
#override
String toString() => '$someProperty->$someValue';
}
I have the following two lists of String:
{APPLE, ORANGE, BANANA} //call it keyList
{APPLE123, ORANGEXXX, 1APPLE, APPLEEEE} //call it valueList
Desired output is an HashMap<String, List<String>> like this:
<APPLE, {APPLE123, 1APPLE, APPLEEEE}>
<ORANGE, {ORANGEXXX}>
<BANANA, {}> //also <key, null> is accepted
I have implemented this solution(it works)
HashMap<String, List<String>> myMap = new HashMap<>();
keyList.forEach(key -> {
List<String> values = valueList.stream()
.filter(value -> value.contains(key))
.collect(Collectors.toList());
myMap.put(key, values);
});
Given the assumption that a value is related to only one key (it's a constraint of my domain), is this the best solution in java8 , in terms of performance and/or code cleaning ?
Can it be tuned in some way?
If you can safely assume that each value is associated with a key, and only one key, you can go into the following direction:
Pattern p = Pattern.compile(String.join("|", keyList));
Map<String, List<String>> map = valueList.stream()
.collect(Collectors.groupingBy(s -> {
Matcher m = p.matcher(s);
if(!m.find()) throw new AssertionError();
return m.group();
}));
map.forEach((k,v) -> System.out.println(k+": "+v));
If the keys may contain special characters which could get misinterpreted as regex constructs, you can change the preparation code to
Pattern p = Pattern.compile(
keyList.stream().map(Pattern::quote).collect(Collectors.joining("|")));
The collect operation does only create the groups for existing values. If you really need all keys to be present, you can use
Map<String, List<String>> map = valueList.stream()
.collect(Collectors.groupingBy(s -> {
Matcher m = p.matcher(s);
if(!m.find()) throw new AssertionError();
return m.group();
},
HashMap::new, // ensure mutable map
Collectors.toList()
));
keyList.forEach(key -> map.putIfAbsent(key, Collections.emptyList()));
or
Pattern p = Pattern.compile(
keyList.stream().map(Pattern::quote)
.collect(Collectors.joining("|", ".*(", ").*")));
Map<String, List<String>> map = valueList.stream()
.map(p::matcher)
.filter(Matcher::matches)
.collect(Collectors.groupingBy(m -> m.group(1),
HashMap::new, // ensure mutable map
Collectors.mapping(Matcher::group, Collectors.toList())
));
keyList.forEach(key -> map.putIfAbsent(key, Collections.emptyList()));
I need to add data to a Map or HashMap before a for...loop, add data to the Map during the for...loop and then create the document with all of the data after the loop.
In Java for Android I used:
Map<String, Object> createDoc = new HashMap<>();
createDoc.put("type", type);
createDoc.put("title", title);
for (int x = 0; x < sArray.size(); x++) {
createDoc.put("data " + x,sArray.get(x));
}
firebaseFirestoreDb.collection("WPS").add(createDoc);
My question is, how would I create the document and immediately get the ID of it to then update/merge it with the rest of the data? Or is there a way to add data to a Map in Dart?
The only thing I've found in Dart is:
Map<String, Object> stuff = {'title': title, 'type': type};
and in the for...loop:
stuff = {'docRef $x': docId};
and after the for...loop:
Firestore.instance.collection('workouts').add(stuff);
which creates a document with only the last entry from the for...loop.
I also imported dart:collection to use HashMap, but it won't let me use
Map<String, Object> newMap = new HashMap<>();
I get the error: "A value of type 'HashMap' can't be assigned to a variable of type 'Map<String, Object>'"
Thank you in advance!
An equivalent block of code to what you wrote in Java, for Dart, is:
Map<String, Object> createDoc = new HashMap();
createDoc['type'] = type;
createDoc['title'] = title;
for (int x = 0; x < sArray.length; x++) {
createDoc['data' + x] = sArray[x];
}
Of course, Dart has type inference and collection literals, so we can use a more short-hand syntax for both. Let's write the exact same thing from above, but with some more Dart (2) idioms:
var createDoc = <String, Object>{};
createDoc['type'] = type;
createDoc['title'] = title;
for (var x = 0; x < sArray.length; x++) {
createDoc['data' + x] = sArray[x];
}
OK, that's better, but still is not using everything Dart provides. We can use the map literal instead of writing two more lines of code, and we can even use string interpolation:
var createDoc = {
'type': type,
'title': title,
};
for (var x = 0; x < sArray.length; x++) {
createDoc['data$x'] = sArray[x];
}
I also imported dart:collection to use HashMap, but it won't let me
use
Map<String, Object> newMap = new HashMap<>(); I get the error: `"A value of type 'HashMap' can't be assigned to a variable of type
'Map'`"
There is no such syntax new HashMap<> in Dart. Type inference works without it, so you could just write Map<String, Object> map = new HashMap(), or like my above example, var map = <String, Object> {}, or even better, var map = { 'type': type }, which will type the map for you based on the key and value.
I hope that helps!
I have a Map of the following type
public class MapUtils {
private Map<String, Integer> queryCounts = new HashMap<>();
public void averageCounters(){
int totalCounts = queryCounts.values().stream().reduce(0, Integer::sum);
queryCounts = queryCounts.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
(Map.Entry::getValue)/totalCounts
));
}
This does not compile and shows error in this line (Map.Entry::getValue)/totalCounts. How do I fix this? Is there a better way to get achieve average over Map using Java 8 API?
EDIT:
Is this a better approach?
queryCounts.entrySet()
.forEach(entry -> queryCounts.put(entry.getKey(),
entry.getValue()/totalCounts));
If you want in-place modification, it's much better to use Map.replaceAll instead of Stream API:
int totalCounts = queryCounts.values().stream()
.collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
However in your case this solution is problematic as division results will be rounded to an int number, thus you almost always will got zeroes in the result. Actually there's the same problem in your code. You probably want to have Map<String, Double> as the resulting type. So you probably need to create a completely new Map:
Map<String, Double> averages = queryCounts.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey,
e -> ((double)e.getValue())/totalCounts));
An alternative would be to have queryCounts declared as Map<String, Double> in the first place. This way you can use replaceAll:
double totalCounts = queryCounts.values().stream()
.collect(Collectors.summingDouble(Double::doubleValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Finally there's also one more alternative which is the most efficient, but dirty. Your code assumes that original (non-averaged) queryCounts are unnecessary after averageCounters() is called. Thus you can keep queryCounts as Map<String, Integer> (which is more effective than counting to Map<String, Double>), but then change the Map values type like this:
double totalCounts = queryCounts.values().stream()
.collect(Collectors.summingInt(Integer::intValue));
Map<String, Object> map = (Map<String, Object>)queryCounts;
map.replaceAll((k, v) -> ((Integer)v)/totalCounts);
Map<String, Double> averages = (Map<String, Double>)map;
queryCounts = null;
The similar trick is performed in JDK inside the Collectors.groupingBy implementation.
I'd like to persist a bare Map to vertex properties.
The motivation is that I don't know in advance which properties the map will contain.
And storing one vertex per property doesn't seem effective.
How would I do that?
interface Foo {
#Properties...?
Map<String,String> getProperties();
#Properties
Map<String,String> addProperty();
}
Perhaps through method handlers. How?
And is there any native support?
I've added support for it using the handlers.
See the Windup project.
https://github.com/windup/windup/pull/157
This is how it looks in models.
This one stores the map in the props of given frame's vertex, using a prefix map:
#TypeValue("MapInAdjPropsModelMain")
public interface MapMainModel extends WindupVertexFrame
{
#InProperties(propPrefix = "map") void setMap(Map<String, String> map);
#InProperties(propPrefix = "map") Map<String, String> getMap();
}
And this one stores the map in an adjacent vertex, hence can store multiple maps:
#TypeValue("MapInAdjPropsModelMain")
public interface MapMainModel extends WindupVertexFrame
{
#InAdjacentProperties(edgeLabel = "map")
void setMap(Map<String, String> map);
#InAdjacentProperties(edgeLabel = "map")
Map<String, String> getMap();
#InAdjacentProperties(edgeLabel = "map2")
void setMap2(Map<String, String> map);
#InAdjacentProperties(edgeLabel = "map2")
Map<String, String> getMap2();
}