My intention is to format the name key in an existing Map value.
Supposed the current key value is in UpperCase but I wanted to make it LowerCase
From this
Map<String, String> foo = {
"A" : "valueOne",
"B" : "valueTwo",
};
print(foo); // output: {"A" : "valueOne", "B" : "valueTwo"}
To this
print(foo); // output: {"a" : "valueOne", "b" : "valueTwo"}
Here's the method I tried:
Map<String, String> foo = {
"A" : "valueOne",
"B" : "valueTwo",
};
foo.forEach((key, value) {
key = key.toString().toLowerCase();
value = value;
});
... something something
also tried to assign the forEach as a value
Map<String, String> foo = {
"A" : "valueOne",
"B" : "valueTwo",
};
var bar = foo.forEach((key, value) {
key = key.toString().toLowerCase();
value = value;
});
print(bar); // Failed because forEach Datatype is `void`
... something something
also tried
Map<String, String> foo = {
"A" : "valueOne",
"B" : "valueTwo",
};
foo.forEach((key, value) {
key = key.toString().toLowerCase();
value = value;
Map<String, String> bar = {key: value};
print(bar); // `Output: {a: valueOne} {b: valueTwo}` <- is not what I was looking for.
});
... something something
Any suggestions on what to do Next?
First of all, you cannot change a key, you have to remove the old key and add a new key instead.
You can then choose to either update the existing map, or build a new one.
Creating a new one is simpler:
var newMap = {for (var e in oldMap.entries) e.key.toLowerCase() : e.value};
We ignore the risk of having existing keys which are equal after calling toLowerCase, like "Foo", "FOO" and "foo".
Updating the existing map is trickier, but if we ignore the same risks, it can be something like:
// Snapshot the keys to avoid concurrent modification error when iterating.
for (var e in map.entries.toList()) {
var key = e.key;
var lc = key.toLowerCase();
if (lc != key) {
map[lc] = e.value;
map.remove(key);
}
}
Alternatively, use a CanonicalizedMap to begin with, which does the lower-casing for you (and allows you to look up with any casing of the same text).
I found the answer already.
Map<String, String> foo = {
"A": "valueOne",
"B": "valueTwo",
};
Map<String, dynamic> bar = {};
foo.keys.toList().forEach((key) {
bar.addAll({key.toString().toLowerCase(): foo[key]});
});
print(bar);
}
Related
Is there an elegant way to access the first property of an object...
where you don't know the name of your properties
without using a loop like for .. in or jQuery's $.each
For example, I need to access foo1 object without knowing the name of foo1:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
Object.values(obj)[0]; // returns 'someVal'
Using this you can access also other properties by indexes. Be aware tho! Object.keys or Object.values return order is not guaranteed as per ECMAScript however unofficially it is by all major browsers implementations, please read https://stackoverflow.com/a/23202095 for details on this.
Try the for … in loop and break after the first iteration:
for (var prop in object) {
// object[prop]
break;
}
You can also do Object.values(example)[0].
You can use Object.values() to access values of an object:
var obj = { first: 'someVal' };
Object.values(obj)[0]; // someVal
Use Object.keys to get an array of the properties on an object. Example:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var keys = Object.keys(example); // => ["foo1", "foo2", "foo3"] (Note: the order here is not reliable)
Documentation and cross-browser shim provided here. An example of its use can be found in another one of my answers here.
Edit: for clarity, I just want to echo what was correctly stated in other answers: the key order in JavaScript objects is undefined.
A one-liner version:
var val = example[function() { for (var k in example) return k }()];
There isn't a "first" property. Object keys are unordered.
If you loop over them with for (var foo in bar) you will get them in some order, but it may change in future (especially if you add or remove other keys).
The top answer could generate the whole array and then capture from the list. Here is an another effective shortcut
var obj = { first: 'someVal' };
Object.entries(obj)[0][1] // someVal
Solution with lodash library:
_.find(example) // => {name: "foo1"}
but there is no guarantee of the object properties internal storage order because it depends on javascript VM implementation.
Here is a cleaner way of getting the first key:
var object = {
foo1: 'value of the first property "foo1"',
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
let [firstKey] = Object.keys(object)
console.log(firstKey)
console.log(object[firstKey])
if someone prefers array destructuring
const [firstKey] = Object.keys(object);
No. An object literal, as defined by MDN is:
a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).
Therefore an object literal is not an array, and you can only access the properties using their explicit name or a for loop using the in keyword.
To get the first key name in the object you can use:
var obj = { first: 'someVal' };
Object.keys(obj)[0]; //returns 'first'
Returns a string, so you cant access nested objects if there were, like:
var obj = { first: { someVal : { id : 1} }; Here with that solution you can't access id.
The best solution if you want to get the actual object is using lodash like:
obj[_.first(_.keys(obj))].id
To return the value of the first key, (if you don't know exactly the first key name):
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
if you know the key name just use:
obj.first
or
obj['first']
This has been covered here before.
The concept of first does not apply to object properties, and the order of a for...in loop is not guaranteed by the specs, however in practice it is reliably FIFO except critically for chrome (bug report). Make your decisions accordingly.
I don't recommend you to use Object.keys since its not supported in old IE versions. But if you really need that, you could use the code above to guarantee the back compatibility:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
}})()};
Feature Firefox (Gecko)4 (2.0) Chrome 5 Internet Explorer 9 Opera 12 Safari 5
More info: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
But if you only need the first one, we could arrange a shorter solution like:
var data = {"key1":"123","key2":"456"};
var first = {};
for(key in data){
if(data.hasOwnProperty(key)){
first.key = key;
first.content = data[key];
break;
}
}
console.log(first); // {key:"key",content:"123"}
If you need to access "the first property of an object", it might mean that there is something wrong with your logic. The order of an object's properties should not matter.
A more efficient way to do this, without calling Object.keys() or Object.values() which returns an array:
Object.prototype.firstKey = function () {
for (const k in this) {
if (Object.prototype.hasOwnProperty.call(this, k)) return k;
}
return null;
};
Then you can use it like:
const obj = {a: 1, b: 2, c: 3}
console.log(obj.firstKey()) //=> 'a'
This doesn't necessarily return the first key, see Elements order in a "for (… in …)" loop
we can also do with this approch.
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
Object.entries(example)[0][1];
This is an old question but most of the solutions assume that we know the attribute's name which it is not the case for example if you are trying to visualize data from files that the user can upload or similar cases.
This is a simple function that I use and works in both cases that you know the variable and if not it will return the first attribute of the object (sorted alphabetically)
The label function receives an object d and extract the key if exits, otherwise returns the first attribute of the object.
const data = [
{ label: "A", value: 10 },
{ label: "B", value: 15 },
{ label: "C", value: 20 },
{ label: "D", value: 25 },
{ label: "E", value: 30 }
]
const keys = ['label', 0, '', null, undefined]
const label = (d, k) => k ? d[k] : Object.values(d)[0]
data.forEach(d => {
console.log(`first: ${label(d)}, label: ${label(d, keys[0])}`)
})
keys.forEach(k => {
console.log(`label of ${k}: ${label(data[0], k)}`)
})
For values like 0, '', null, and undefined will return the first element of the array.
this is my solution
const dataToSend = {email:'king#gmail.com',password:'12345'};
const formData = new FormData();
for (let i = 0; i < Object.keys(dataToSend).length; i++) {
formData.append(Object.keys(dataToSend)[i],
Object.values(dataToSend)[i]);
}
console.log(formData);
Any reason not to do this?
> example.map(x => x.name);
(3) ["foo1", "foo2", "foo3"]
Basic syntax to iterate through key-value gracefully
const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// expected output:
// "a: somestring"
// "b: 42"
As others have pointed out, if the order of properties is important, storing them in an object is not a good idea. Instead, you should use an array via square brackets. E.g.,
var example = [ {/* stuff1 */}, { /* stuff2 */}, { /* stuff3 */}];
var first = example[0];
Note that you lose the 'foo' identifiers. But you could add a name property to the contained objects:
var example = [
{name: 'foo1', /* stuff1 */},
{name: 'foo2', /* stuff2 */},
{name: 'foo3', /* stuff3 */}
];
var whatWasFirst = example[0].name;
For those seeking an answer to a similar question, namely: "How do I find one or more properties that match a certain pattern?", I'd recommend using Object.keys(). To extend benekastah's answer:
for (const propName of Object.keys(example)) {
if (propName.startsWith('foo')) {
console.log(`Found propName ${propName} with value ${example[propName]}`);
break;
}
}
I have a problem converting a list to a Map, I'm using map.fromiterable to convert my list, but it only can show 1 data and 1 key.
This is what it output:
[{id_apd: 4}]
here is my class Model for the list,
class APDPengajuanModel {
final int id_apd;
final int jumlah;
APDPengajuanModel({this.id_apd, this.jumlah});
}
and here is my function to convert the list to a map.
void toMap() {
Map<String, dynamic> id_apd = Map.fromIterable(
Provider.of<myProvider>(context, listen: false).listAPD,
key: (v) => "id_apd",
value: (v) => v.id_apd.toString());
print(id_apd);
}
from my code above, it only can show id_apd and can't show jumlah variables from the list.
please help how to show id_apd and jumlah together :)
this is how the output that i hope, but not shows like this.
[
{
"id_apd": 1,
"jumlah" : 15
}
]
I think that there is difference between what title means and output you hope.
This is code for result you hope.
var result = listAPD.map((item) {
return { "id_apd": item.id_apd, "jumlah" : item.jumlah };
}).toList();
print(result);
I assume you have 2 lists that you want to combine into a list map
final listPengajuan = ["id_apd","jumlah"];
final nilai = [1,5];
final paket = {};
final hasil = [];
for(var i = 0; i < listPengajuan.length; i++){
paket.addAll({listPengajuan[i]:nilai[i]});
}
hasil.add(paket);
print(JsonEncoder.withIndent(" ").convert(hasil));
result :
[
{
"id_apd": 1,
"jumlah": 5
}
]
I think that because you added list item to map by same key "id_apd".
ex )
<List>
[{id_apd: 2}, {id_apd: 3}, {id_apd: 4}]
<Map>
iteration 1: { id_apd: 2}
iteration 2: { id_apd: 3}
iteration 3: { id_apd: 4}
Having such json - "Config.json":
{
"Configuration" :
{
"_id" :
{ "id" : 40,
"version" : 100
},
"companyCode" : "AB",
"crewType" : "STANDARD",
"modifiedByStaffId" : "12030405",
"lastModifiedTimestamp" : "2018-07-04T12:17:21Z",
"offDaysAllowed" : true,
"daysAllowed" :
{ "max" : 5,
"min" : 1
},
"offDayQuota" :
{ "per" : "month",
"value" : 20
},
"requestWindow" :
{ "opens" :
{
"value" : 1,
"unit" : "day"
},
"closes" :
{
"value" : 2,
"unit" : "month"
}
},
"reasons" : [ "wedding", "funeral", "illness" ],
"supportingDocuments" :
{
"email" : "samplemail#gmail.com",
"canSubmit" : true
},
"changeReasonCode" : "TODR"
}
}
The problem:
I receive the json response, then I want to change his nested values and send it back, so I want to instantiate the object from this "Config.json" file and be able to easily set/change and get his nested values. For example config.setDaysAllowed_Max(4)
According to this article: http://www.baeldung.com/jackson-nested-values
I tried to use the method "Mapping with Annotations" with usage of JsonProperty, so I have a Config.groovy class:
class OffDayConfig {
Object configuration
Integer id
Integer version
String companyCode
String crewType
String modifiedByStaffId
String lastModifiedTimestamp
boolean offDaysAllowed
Integer daysAllowed_Max
Integer daysAllowed_Min
String offDayQuota_Per
Integer offDayQuota_Value
Integer opensValue
String opensUnit
Integer closesValue
String closesUnit
List<String> reasons
String supportingDocumentsEmail
String supportingDocumentsCanSubmit
String changeReasonCode
#SuppressWarnings("unchecked")
#JsonProperty("configuration")
def unpackNested(Object configuration) {
Map<String, Integer> _id = (Map<String, Integer>) configuration._id
this.id = _id.get("id")
this.version = _id.get("version")
this.companyCode = configuration.get("companyCode")
this.crewType = configuration.get("crewType")
this.modifiedByStaffId = configuration.get("modifiedByStaffId")
this.lastModifiedTimestamp = configuration.get("lastModifiedTimestamp")
this.offDaysAllowed = configuration.get("offDaysAllowed")
Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ")
this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max")
this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min")
Map<String, Object> offDayQuota = (Map<String, Object>) configuration.get("offDayQuota")
this.offDayQuota_Per = offDayQuota.get("per")
this.offDayQuota_Value = offDayQuota.get("value")
Map<String, Object> requestWindow = (Map<String, Object>) offDayQuota.get("requestWindow")
Map<String, Object> opens = (Map<String, Object>) requestWindow.get("opens")
this.opensValue = opens.get("value")
this.opensUnit = opens.get("unit")
Map<String, Object> closes = (Map<String, Object>) requestWindow.get("closes")
this.closesValue = closes.get("value")
this.closesUnit = closes.get("unit")
this.reasons = configuration.get("reasons")
Map<String, Object> supportingDocuments = (Map<String, Object>) configuration.get("supportingDocuments")
this.supportingDocumentsEmail = supportingDocuments.get("email")
this.supportingDocumentsCanSubmit = supportingDocuments.get("canSubmit")
this.changeReasonCode = configuration.get("changeReasonCode")
}
}
Then I use an ObjectMapper to transform our source JSON, which exists as the String "json" within the test class:
Map offDayConfigMap = DataSource.getTestData(DataSourceType.OFF_DAY_CONFIG) //This line reads json file and creates the Map from it
String json = JsonOutput.toJson(offDayConfigMap)
OffDayConfig offDayConfig = new ObjectMapper().readerFor(OffDayConfig.class).readValue(json)
But the problem occurs in the method readValue(). I can't figure out why and what is the reason. Here is the log:
com.fasterxml.jackson.databind.JsonMappingException: Cannot invoke method get() on null object
at [Source: (String)"{"Configuration":{"_id":{"id":40,"version":100},"changeReasonCode":"TODR","companyCode":"AB","crewType":"STANDARD","daysAllowed":{"max":5,"min":1},"lastModifiedTimestamp":"2018-07-04T12:17:21Z","modifiedByStaffId":"12030405","offDayQuota":{"per":"month","value":20},"offDaysAllowed":true,"reasons":["wedding","funeral","illness"],"requestWindow":{"closes":{"unit":"month","value":2},"opens":{"unit":"day","value":1}},"supportingDocuments":{"canSubmit":true,"email":"samplemail#gmail.com"}}}"; line: 1, column: 488] (through reference chain: ......................Config["Configuration"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:588)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:576)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:134)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1608)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1216)
at ..................................Test.setupSpec(Test.groovy:42)
Caused by: java.lang.NullPointerException: Cannot invoke method get() on null object
at ..................................Config.unpackNested(Config.groovy:42)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:132)
... 5 more
Dots represents the packages.
I would be grateful for help or for suggestion how to do it in another way, cause I need good way to do so, cause I will have several json files to handle in that way.
Just a quick guess, the NPE is due to
Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ")
this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max")
this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min")
You have a space after the "daysAllowed" string, this causes daysAllowed to be null as there is no proper key in your json file to match "daysAllowed ", and any subsequent action you take is a invoking a get() on a null object.
I would suggest, if not already, using a proper IDE with a debugging tool and traversing the code line by line and see what happens.
Thanks to #Boaz answer I debugged my code and found 3 mistakes:
Map<String, Integer> daysAllowed = (Map<String, Integer>) configuration.get("daysAllowed ") -> the space after "daysAllowed " -> "daysAllowed"
Map<String, Object> requestWindow = (Map<String, Object>) offDayQuota.get("requestWindow") -> Here I should write configuration.get("requestWindow") instead of offDayQuota.get("requestWindow"), so "offDayQuota" -> "configuration"
this.daysAllowed_Max = daysAllowed.get("daysAllowed_Max") -> "max" instead of "daysAllowed_Max"
this.daysAllowed_Min = daysAllowed.get("daysAllowed_Min") -> "min" instead of "daysAllowed_Min"
It works, but I don't know how to convert this flat object into the same json again.
I passed the following object:
var myVar = { typeA: { option1: "one", option2: "two" } }
I want to be able to pull out the key typeA from the above structure.
This value can change each time so next time it could be typeB.
So I would like to know if there is any way to do that
I was able to solve using 'keys'
for a json example like this:
{
"1-0001": {
"name": "red",
"hex": "FF0000"
},
"1-0002": {
"name": "blue",
"hex": "0000FF"
},
"1-0003": {
"name": "green",
"hex": "008000"
}
}
I was able to use
Map<String, dynamic> decoded = json.decode(jsonString);
for (var colour in decoded.keys) {
print(colour); // prints 1-0001
print(decoded[colour]['name']); // prints red
print(decoded[colour]['hex']); // prints FF0000
}
To get all filenames you can use:
var data = ...
var filenames = [];
for(var i = 0; i < data.length; i++) {
var item = data[0]['files'];
var key = item.keys.first;
var filename = item[key]['filename'];
filenames.add(filename);
}
print(filenames);
You need to define a data type.
It is basically a map of (key value-pair) where key is changed as stated in question typeA or typeB
This Object has 2 properties option1 and option2 which is also strings.
Here is the sample code to construct model and how to use it
import 'package:TestDart/TestDart.dart' as TestDart;
main(List<String> arguments) {
var map = new Map<String, MyObject>();
map['typeA'] = new MyObject("one", "two");
map['typeB'] = new MyObject("one", "two");
print(map['typeA'].toString());
print(map['typeA'].toString());
}
class MyObject {
String _option1;
String _option2;
MyObject(this._option1, this._option2);
String get option2 => _option2;
String get option1 => _option1;
#override
String toString() {
return 'MyObject{option1: $_option1, option2: $_option2}';
}
}
Relevant answer
map.forEach((key, value) {
print("Key : ${key} value ${value}");
});
I have a complex JSON Object like this:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {
CustomerID: 400, CustomerName: "John"
} }
] } ] };
I am trying to do two things:
Declare this object but with the variable data empty
With a loop, add items dynamically to the data object,
How can I do it?
This isn't too complex an object. And it isn't JSON until it's converted into a string.
Right now, it's just plain-ol' JS objects and arrays.
Breaking that down into its elements might look like this:
var requestData = {};
requestData.__batchRequests = [];
requestData.__batchRequests[0] = {};
requestData.__batchRequests[0].__changeRequests = [];
requestData.__batchRequests[0].__changeRequests[0] = {};
requestData.__batchRequests[0].__changeRequests[0].requestUri = "Customers";
requestData.__batchRequests[0].__changeRequests[0].method = "POST";
requestData.__batchRequests[0].__changeRequests[0].headers = { "Content-ID" : "1" };
requestData.__batchRequests[0].__changeRequests[0].data = {};
Aside from the repeats, what do you see?
Personally, I see that __changeRequests[0] is an object as simple as:
var changeRequest = {
requestUri : "Customers",
method : "POST",
headers : { "Content-ID" : "1" },
data : {}
};
I also see that I can just push that onto my array of change requests:
requestData.__batchRequests[0].__changeRequests.push(changeRequest);
Right?
I also know that my changeRequest variable still points to the one that I just added to the array, and whatever I change on the object will show up as changed in the array's reference to the object, too:
changeRequest.data.CustomerName = "Bob";
changeRequest.data.CustomerID = "204";
requestData.__/*...*/changeRequests[0].data.CustomerName; // Bob
So how about writing yourself some helper-functions?
function extend (obj, additions) {
var key;
for (key in obj) { if (additions.hasOwnProperty(key)) {
obj[key] = additions[key];
}
}
function makeChangeRequest (url, method, headers, data) {
var request = {
requestUri : url,
method : method,
headers : {},
data : {}
};
extend(request.headers, headers);
extend(request.data, data);
return request;
}
function getBatch (num) { return requestData.__batchRequests[num]; }
var changeReq = makeChangeRequest("Customers",
"POST",
{ "Content-ID" : "1" },
{ CustomerName : "Bob", CustomerID : "2012" });
var batch = getBatch(0);
batch.__changeRequests.push(changeReq);
If you want to add more data to changeReq.data later:
extend(changeReq.data, { Address : "33 Nowhere Rd.", City : "Splitsville" });
For the first part of your question, you can initialize data with an empty associative array:
var requestData = { __batchRequests: [ { __changeRequests: [
{ requestUri: "Customers", method: "POST", headers: { "Content-ID": "1" }, data: {} }
] } ] };
This next part assumes, perhaps incorrectly, that you can use jQuery. It also assumes that you have an array containing all of the relevant key value pairs.
var customerDeetsArray =[{CustomerID: 400}, {CustomerName: "John"}];
for (var i in customerDeetsArray) {
requestData.data = $.extend(requestData.data, customerDeetsArray[i]);
}
See working example which makes use of console.debug:
http://jsfiddle.net/4Rh72/6/