In my store I have multiple lists of ids which reference to normalized entities.
It looks something like this:
{
list1: [ 1 ],
list2: [],
//other lists
entities: {
1:{data},
...
}
}
Users can edit items and can select in which list the item should be. I can't find an elegant way to move the item from one list to another if the user changed the list while editing.
To move an item I have to remove the item-id from the old list and add it to the new one.
How should I remove the Id from the old list after having written it into the new one? Looking into every list for the Id and if found removing it seems a bit wrong to me.
EDIT:
To explain my use case further:
There can be n lists, which are dates, for example "08-17-2016" and the items in it are events. A user can change the date of an event and so the event needs to move from one date to the other.
I would simply use Array.prototype.filter and check with Array.prototype.indexOf in which list this Id is present:
function moveOrAdd(idToMove, list) {
if (list.indexOf(idToMove) > -1) {
// idToMove was in list so remove
return list.filter(id => id !== idToMove);
} else {
// idToMove wasn't in list so add it
return [...list, idToMove];
}
}
// your store then, assuming an array of id to move or delete
[1, 2, 3 ... 2000].forEach(
index => {
{
list1: [...moveOrAdd(index, list1)],
list2: [...moveOrAdd(index, list2)],
/// etc...
}
}
);
Related
basically the title.
If I had to find what I know as a single field,
a.any {
it.name == "user"
}
Now I've a listOf(Groups)
Which contains a unique ID
I want to check
if user.groups.anyItemInThisList.UNIQUEID == otheruser.groups.anyItemInThisList.UNIQUEID
My data looks like this
{
"groups":[
{
"id":4
"group":"Test Group",
"role":"creator",
"member_count":1,
"userType":"local"
}
]
}
To rephrase your question (making sure I understand correctly), you have two Lists of the same kind of item, and you want to determine if there is any value of the id property of an item that appears in both lists.
To do this with simple code, but O(n^2) time, you could use this. It iterates all items from a and for each item it iterates b to see if there are any matches.
val result = a.any { x1 -> b.any { x2 -> x1.id == x2.id} }
To do it in O(n) you can do it with a Set. This creates a set of the names from the first list, and then it only has to iterate the second list once to see if any of the names are in the first set.
val aIds = a.mapTo(HashSet(a.size)) { it.id }
val result = b.any { it.id in aIds }
How can ı equalize my array ıd and my value ıd and access value.name I didn't do it
This is my code:
activity(val) {
var act = this.items.map(function (val) {
if (element.ActivityID== val) {
return element.ActivityName
}
return act
});
Perhaps this?
activity (val) {
const activity = this.items.find(item => item.ActivityID === val)
return activity && activity.ActivityName
}
This just finds the item with the corresponding ActivityID and then returns its ActivityName.
Your original code contained several possible mistakes:
Two different things called val.
element doesn't appear to be defined.
The return act was inside the map callback. The activity method itself wasn't returning anything.
Not really clear why you were using map to find a single item. map is used to create a new array with the same length as the original array with each item in the new array determined by the equivalent item in the original array. It 'maps' the items of the input array to the items in the output array.
I have created a listView and button and when I click the button it adds an item to listView.
The problem is I don't want actually to repeat the same item in the list.
I've tried the .contains method but it didn't work.
I want a good solution please,
There are different ways to achieve this:
1) Iterate the list and check if every element doesn't have the
properties you consider equal:
items = [Item(id: 1), Item(id: 2)];
newItem = Item(id: 2);
if (items.every((item) => item.id != newItem.id)) {
items.add(newItem);
}
2) Use contains() and override == operator (and override hashCode too)
in the object class with the properties you consider equal.
items = [Item(id: 1), Item(id: 2)];
newItem = Item(id: 2);
if (!items.contains(newItem)) {
items.add(newItem);
}
// inside Item class
#override
bool operator ==(other) {
return this.id == other.id;
}
#override
int get hashCode => id.hashCode;
3) Instead of List use Set, where each element can occur only once. Its default implementation is LinkedHashSet that keeps track of the order.
Instead of List, Use Set.
void main() {
Set<String> currencies = {'EUR', 'USD', 'JPY'};
currencies.add('EUR');
currencies.add('USD');
currencies.add('INR');
print(currencies);
}
output: {EUR, USD, JPY, INR} // unique items only
Reference: Set<E> class
Check if the List already contains the element before you add it:
https://api.flutter.dev/flutter/dart-core/List-class.html
if(!List.contains(element) { add }
The contains method checks for equality, not for reference, so it must work as long as you compare a similar element. If your code isn't working, please provide it to us. Thanks.
If your list contains custom objects you may need to override the equality operator in the custom class.
You could also use a Set instead of a List.
So I'm using ngrx for managing the state in my application. I tried to add a new property (selected shifts) which should look like this:
state: {
shifts: {
selectedShifts: [
[employeeId]: [
[shiftId]: shift
]
]
}
}
at the moment, my state looks like this:
state: {
selectedShifts: {
[employeeId]: {
[shiftId]: shift
}
}
}
so as you can see, my "selected shift" is a property, not an array - which makes it diffictult to add/remove/query the state.
How do I compose the state to look like I want it?
This is what I tried in the reducer:
return {
...state,
selectedShifts: {
...state.selectedShifts,
[action.payload.employeeId]: {
...state.selectedShifts[action.payload.employeeId],
[action.payload.shiftId]: action.payload[shift.shiftId]
}
}
};
Now when I try to return the state in the way I'd like to, this is the result:
state: {
selectedShifts: {
[action.payload.employeeId]:
[0]: {[action.payload.shiftId]: { shift }}
}
}
What am I missing here? When I try to replace the {} items which should be [] this error comes up: "," expected.
Oh yea, I would like the index of the array to be the id of the specific shift and not [0], [1]...
Is this possible at all?
Would it be a bad idea to change the index from numerics to the actual shift's id?
Array length kind of miss behaves when you add data at numeric index points. This might get you into problems with array methods using length join, slice, indexOf etc. & array methods altering length push, splice, etc.
var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3
When setting a property on a JavaScript array when the property is a valid array index and that index is outside the current bounds of the array, the engine will update the array's length property accordingly:
fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 6
There is no problem selecting / updating state from object, it's just a bit different from what you're probably used to. With straight hashmap { objectId: Object } finding the required object to update / remove is the fastest possible if changes are defined for object id.
I know your problem is related to NGRX but reading Redux immutable patterns is going to definitely help you out here for add / update / remove objects from the state. https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
Generally you don't want to have arrays in state ( at least large arrays ) object hashmaps are a lot better.
To get array of your selected user shifts for views you could do something like. Note this is not a shift indexed array just array of shifts under userId property. From original state form following state.
state: {
selectedShifts: {
[employeeId]: {
[shiftId]: shift
}
}
}
const getSelectedShiftsAsArray = this.store.select( getSelectedShifts() )
.map(
userShifts => {
// get array of object ids
const userIds = Object.keys( userShifts );
const ret = {};
for( const userId of userIds ) {
const collectedShifts = [];
// convert Dictionary<Shift> into a Shift[]
// get array of shift ids
const shiftIds = Object.keys( userShifts[userId] );
// map array of shift ids into shift object array
collectedShifts = shiftIds.map( shiftId => userShifts[shiftId] );
// return value for a userId
ret[userId] = collectedShifts;
}
return ret;
});
Code is completely untested and just for a reference one level up from pseudocode. You could easily convert that into a NGRX selector though. The state is there just for the storage, how you model it for use in components is upto selector functions & components themselves.
If you really really need it you could add.
ret[userId].shiftIds = shiftIds;
ret[userId].shifts = collectedShifts;
But it really depends on how you plan to use these.
From my personal experience I would separate shift entities from selectedShifts but how you organise your state is completely up to you.
state: {
shifts: {
// contains shift entities as object property map id: entity
entities: Dictionary<Shift>,
selectedShifts: [
[employeeId]: number[] // contains ids for shifts
]
}
}
Now updating / removing and adding a shift would just be setting updated data into path shifts.entities[entityId]
Also selectedShifts for employeeId would be about checking if id is already in there and appending it into an array if it wasn't. ( If these arrays are humongous I'd go with object hash here too for fast access. <employeeId>: {shiftId:shiftId} ).
Check also:
redux: state as array of objects vs object keyed by id
I have a state "Bill" and I want to delete one of item in "Product" with "ProductID". So how can I do it?
Bill = {
"Bill_ID" : "a00231",
"Products" : [
{
"ProductID" : "P0203",
"ProductName" : "ABCD"
},
{
"ProductID" : "P023243",
"ProductName" : "ZYZ"
}
]
}
How can I update the state after delete product item?
I think you could use thepop() method. You can pop the last element from your products array and look at the popped element. Something like:
var poppedElement = Bill.Products.pop();
console.log(Bill) //Bill withoug last Products element
console.log(poppedElement) //just the last element of Products
Not sure if this will work completely off the top of my head, but hopefully will give you a starting place at least :)
Check out this link for more info:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop
Let me know how it goes!
You can use filter on bill.products array, like following (note it must be != not ==)
bill.products.filter(x => x != yourDesiredToBeDeletedId)
Treat this.state as if it were immutable
Since your state contains an array within an object, I suggest to use lodash's cloneDeep.
let newBill = _.cloneDeep(this.bill);
newBill.products = newBill.products.filter(x => x != yourDesiredToBeDeletedId);
this.setState(bill: newBill);