Convert Object Array to Hash Map, Indexed by an Attribute Value of the Object

JavaScript: Convert array of objects into hashmap

This could be achieved by calling reduce on your array of values (ie data), to obtain the required hash map (where ID is the key and value is the corresponding LABEL):

const data = [{ID: 0, LABEL: 'turbo'},{ID: 1, LABEL: 'classic'},{ID: 7, LABEL: 'unknown'}];
const hashMap = data.reduce((result, item) => { return { ...result, [ item.ID ] : item.LABEL };}, {});
const hashMapJson = JSON.stringify(hashMap);
console.log('hashMap', hashMap);console.log('hashMapJson', hashMapJson); /*More concise syntax:console.log(data.reduce((result, { ID, LABEL }) => ({ ...result, [ ID ] : LABEL }), {}))*/

Transform array of objects to a map indexed by object key

To filter the keys based on which have a string value you can't use Extarct that filters the keys which are strings (not number or symbol). You can use KeyOfType described here

type KeyOfType<T, V> = keyof {
[P in keyof T as T[P] extends V? P: never]: any
}
function indexArrayByKey<T, K extends KeyOfType<T, string>> (array: T[], key: K): Map<T[K], T> {
return array.reduce((map, obj) => map.set(obj[key], obj), new Map<T[K], T>())
}

Playground Link

We use T[K] instead of string because T[K] could also be a subtype of string so TS would complain at string, but for cases this will work well.

Using .map() to iterate over an array of Object values and reassign to new keys

When mapping the values, instead of constructing an object containing a single property, return an entry pair (an array where the first value is the property, and the second value is the associated value) so that you can turn the array of entries into an object with Object.fromEntries.

const data = React.useMemo(
() =>
props.tableData.map((object) => (
Object.fromEntries(
Object.values(object).map((value, i) => [`col${i + 1}`, value])
)
)),
[props.tableData]
);

This depends on the properties in your input objects being ordered. While this is usually dependable, it's not a good thing to rely on, and won't work if any of the properties become numeric (eg 1 or 5). Consider if the input object properties could be formatted as an (ordered) array instead.

Convert a List of Object arrays to a List of model Beans grouped by id

To achieve that, we need to group the data by id and name.

For that, we can create an intermediate map. The key of this map should contain two peaces of information id and name. A quick and dirty way is to concatenate these properties as a string, or wrap them with a list or array of Object type, which even is a more nasty workaround.

The proper way of doing this with Java 8 would to define a separate class as data carrier for the keys and with Java 16 onwards, we can define it as a record. But since you've said that MyBean implements equals/hashCode contract based on the id property, we can use it as key in the intermediate map.

For convenience, I've added one method parse() to the MyBean class (if this change is undesirable, you can extract it away from the class and place this logic into the collector).

public class MyBean {
private Integer id;
private String name;
private Map<String, Object> customAttributes;

public MyBean(Integer id, String name) {
this.id = id;
this.name = name;
}

public static MyBean parse(Object[] args) {
return new MyBean((Integer) args[0], (String) args[1]);
}

// getters, setters, equals/hashCode, toString
}

To generate a map using Stream API we can make use of the collector groupingBy(). As a classifier we need to provide function that creates a key - MyBean based on array Object[]. And a downstream collector we can use a collector that combines all "custom attributes" mapped to the same key into a map.

Then we can create a stream over the entries of the intermediate map and parse each entry into MyBean. And finally collect the beans into a list.

That's how it might look like:

public static void main(String[] args) {
List<Object[]> arrays = buildResultList();

List<MyBean> beans = arrays.stream()
.collect(Collectors.groupingBy(
MyBean::parse,
Collector.of(
HashMap::new,
(Map<String, Object> map, Object[] arr) -> map.put((String) arr[2], arr[3]),
(left, right) -> { left.putAll(right); return left; })
))
.entrySet().stream()
.map(entry -> new MyBean(entry.getKey().getId(),
entry.getKey().getName(),
entry.getValue()))
.collect(Collectors.toList());

beans.forEach(System.out::println);
}

And since MyBean is mutable, take advantage of this by reusing the keys. Note that it's not considered to be a good practice to change the state of the attributes of the lambda expression, for that reason to mutate the key of the map a plain I'm using an enhanced for loop.

public static void main(String[] args) {
List<Object[]> arrays = buildResultList();

Map<MyBean, Map<String, Object>> attributesByBean = arrays.stream()
.collect(Collectors.groupingBy(
MyBean::parse,
Collector.of(
HashMap::new,
(Map<String, Object> map, Object[] arr) -> map.put((String) arr[2], arr[3]),
(left, right) -> { left.putAll(right); return left; })
));

List<MyBean> beans = new ArrayList<>();

for (Map.Entry<MyBean, Map<String, Object>> entry : attributesByBean.entrySet()) {
MyBean k = entry.getKey();
k.setCustomAttributes(entry.getValue());
beans.add(k);
}

beans.forEach(System.out::println);
}

Output:

MyBean{id=3, name='name 3', customAttributes={custom_attr_2=custom_attr_2_val_3}}
MyBean{id=1, name='name 1', customAttributes={custom_attr_2=custom_attr_2_val_1}}
MyBean{id=3, name='name 3', customAttributes={custom_attr_3=custom_attr_3_val_3}}
MyBean{id=3, name='name 3', customAttributes={custom_attr_1=custom_attr_1_val_3}}
MyBean{id=2, name='name 2', customAttributes={custom_attr_3=custom_attr_3_val_2}}
MyBean{id=1, name='name 1', customAttributes={custom_attr_3=custom_attr_3_val_1}}
MyBean{id=2, name='name 2', customAttributes={custom_attr_1=custom_attr_1_val_2}}
MyBean{id=1, name='name 1', customAttributes={custom_attr_1=custom_attr_1_val_1}}
MyBean{id=2, name='name 2', customAttributes={custom_attr_2=custom_attr_2_val_2}}

Convert an array of objects to a hash based on a property of the object

JavaScript has Map for maps, so you could do this:

const data = [{"property1": "x","property2": "value1","property3": "value1"},{"property1": "x","property2": "value2","property3": "value2"},{"property1": "y","property2": "value3","property3": "value3"},{"property1": "y","property2": "value4","property3": "value4"}];
const map = new Map(data.map(o => [o.property1, []]));data.forEach(({property1, ...rest}) => map.get(property1).push(rest));const result = Object.fromEntries(map);
console.log(result);

Object values to map

I'm setting the name as a key using "[]" and returning a object with the height

const obj = [
{ id: 1, height: 57, name: 'jhon', state: 'true', time: '' },
{ id: 2, height: 64, name: 'max', state: 'true', time: '' },
{ id: 3, height: 62, name: 'tim', state: 'false', time: '' },
{ id: 4, height: 510, name: 'alex', state: 'false', time: '' },
{ id: 5, height: 510, name: 'frank', state: 'true', time: '' }
]

const result = obj.map(user => {
return {[user.name]: user.height}
})

console.log(result);

Not able to inject Map into the object while testing with Mockito

Only reflection can help with private static field:

@ExtendWith(MockitoExtension.class)
public class FunTest {

private Fun classUndertest = new Fun();

@Test
public void testfoo() throws NoSuchFieldException {
Map<String, Long> test = Map.of("test", 2L);
FieldSetter.setField(classUndertest, Fun.class.getDeclaredField("map1"), test);

long value = classUndertest.foo("test");

Assertions.assertEquals(2L, value);
}
}

Javascript Convert an array to map keyed with the array property and store the corresponding duplicate key values as array

You can use reduce like this:

Check if the accumulator already has key with current a.Record.Account. If yes, push the current item in context to it. Else, add a.Record.Account as a key and then push the item to it.

const input = [{'Key':'1','Record':{'Account':'a','data':'A1'}},{'Key':'2','Record':{'Account':'b','data':'123'}},{'Key':'3','Record':{'Account':'a','data':'A2'}},{'Key':'4','Record':{'Account':'a','data':'A3'}},{'Key':'5','Record':{'Account':'c','data':'123'}}]
const output = input.reduce((acc, a) => ((acc[a.Record.Account] = acc[a.Record.Account] || []).push(a), acc), {})console.log(output);


Related Topics



Leave a reply



Submit