www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.algorithm for changing array values

reply Andre <andre s-e-a-p.de> writes:
Hi,

I checked std.algorithm but have no glue which
functions I can use to rewrite following code
with some nice algorithm functions.

I have an array of structs. I want to check for
a specific key and if found I change the value.
If it is not found I add the entry.

Kind regards
André


struct Data{
	int key;
	int value;
}

void main(){
	Data[] entries = [Data(1,1),Data(2,2)];
	bool found;

	foreach(entry;entries){
		if (entry.key == 3){
			entry.value = 42;
			found = true;
		}
	}

	if (found == false){
		entries ~= Data(3,42);
	}
}
Jan 15 2014
next sibling parent "TheFlyingFiddle" <kurtyan student.chalmers.se> writes:
On Wednesday, 15 January 2014 at 20:34:32 UTC, Andre wrote:
 Hi,

 I checked std.algorithm but have no glue which
 functions I can use to rewrite following code
 with some nice algorithm functions.

 I have an array of structs. I want to check for
 a specific key and if found I change the value.
 If it is not found I add the entry.

 Kind regards
 André


 struct Data{
 	int key;
 	int value;
 }

 void main(){
 	Data[] entries = [Data(1,1),Data(2,2)];
 	bool found;

 	foreach(entry;entries){
 		if (entry.key == 3){
 			entry.value = 42;
 			found = true;
 		}
 	}

 	if (found == false){
 		entries ~= Data(3,42);
 	}
 }
You can use canFind. import std.algorithm; struct Data{ int key; int value; } void main() { auto entries = [Data(1,1),Data(2,2)]; if(!entries.canFind!(x => x.key == 3)) entries ~= Data(3, 42); }
Jan 15 2014
prev sibling next sibling parent reply "anonymous" <anonymous example.com> writes:
On Wednesday, 15 January 2014 at 20:34:32 UTC, Andre wrote:
 Hi,

 I checked std.algorithm but have no glue which
 functions I can use to rewrite following code
 with some nice algorithm functions.

 I have an array of structs. I want to check for
 a specific key and if found I change the value.
 If it is not found I add the entry.

 Kind regards
 André


 struct Data{
 	int key;
 	int value;
 }

 void main(){
 	Data[] entries = [Data(1,1),Data(2,2)];
 	bool found;

 	foreach(entry;entries){
 		if (entry.key == 3){
 			entry.value = 42;
 			found = true;
 		}
 	}

 	if (found == false){
 		entries ~= Data(3,42);
 	}
 }
If you want to stop after the first match: auto f = entries.find!(d => d.key == 3); if(f.empty) entries ~= Data(3,42); else f.front.value = 42; If there can be duplicates and you want to change them all: auto f = entries.filter!(d => d.key == 3); if(f.empty) entries ~= Data(3,42); else foreach(ref e; f) e.value = 42;
Jan 15 2014
next sibling parent Andre <andre s-e-a-p.de> writes:
Am 15.01.2014 21:54, schrieb anonymous:
 If you want to stop after the first match:

 auto f = entries.find!(d => d.key == 3);
 if(f.empty) entries ~= Data(3,42);
 else f.front.value = 42;

 If there can be duplicates and you want to change them all:

 auto f = entries.filter!(d => d.key == 3);
 if(f.empty) entries ~= Data(3,42);
 else foreach(ref e; f) e.value = 42;
Fantastic! Thanks a lot. Kind regards André
Jan 15 2014
prev sibling parent "anonymous" <anonymous example.com> writes:
On Wednesday, 15 January 2014 at 20:54:06 UTC, anonymous wrote:
 On Wednesday, 15 January 2014 at 20:34:32 UTC, Andre wrote:
 Hi,

 I checked std.algorithm but have no glue which
 functions I can use to rewrite following code
 with some nice algorithm functions.

 I have an array of structs. I want to check for
 a specific key and if found I change the value.
 If it is not found I add the entry.

 Kind regards
 André


 struct Data{
 	int key;
 	int value;
 }

 void main(){
 	Data[] entries = [Data(1,1),Data(2,2)];
[...]
 If you want to stop after the first match:

 auto f = entries.find!(d => d.key == 3);
 if(f.empty) entries ~= Data(3,42);
 else f.front.value = 42;

 If there can be duplicates and you want to change them all:

 auto f = entries.filter!(d => d.key == 3);
 if(f.empty) entries ~= Data(3,42);
 else foreach(ref e; f) e.value = 42;
PS: You might want to consider using a different data structure with better performance. An associative array for example: int[int] entries = [1: 1, 2: 2]; entries[3] = 42;
Jan 15 2014
prev sibling next sibling parent reply "Kapps" <opantm2+spam gmail.com> writes:
On Wednesday, 15 January 2014 at 20:34:32 UTC, Andre wrote:
 	foreach(entry;entries){
 		if (entry.key == 3){
 			entry.value = 42;
 			found = true;
 		}
 	}
One thing to keep in mind is that structs are passed by value, so this foreach would be operating on a copy of the entry. So your setting the value to 42 would have no effect. Instead you would need "foreach(ref entry; entries)" in order to have the change take effect (regardless of whether or not you use std.algorithm).
Jan 15 2014
parent "bearophile" <bearophileHUGS lycos.com> writes:
Kapps:

 One thing to keep in mind is that structs are passed by value, 
 so this foreach would be operating on a copy of the entry. So
 your setting the value to 42 would have no effect.

 Instead you would need "foreach(ref entry; entries)" in order to
 have the change take effect (regardless of whether or not you 
 use std.algorithm).
This is a common bug in D code, especially in code of D newbies, but it's also occasionally present in the code of more seasoned D programmers. One solution to avoid it that I suggested is that on default foreach yields const values. So if you want to mutate the value you have to add a "mutable" or "ref": foreach (mutable entry; entries) { Another language solution is to iterate by reference on default, so the ref is implicit: foreach (entry; entries) { And if you want to iterate by value you need to write something different. There are other solutions. But none of them were accepted by Walter :-( Bye, bearophile
Jan 15 2014
prev sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 15 January 2014 at 20:34:32 UTC, Andre wrote:
 Hi,

 I checked std.algorithm but have no glue which
 functions I can use to rewrite following code
 with some nice algorithm functions.

 I have an array of structs. I want to check for
 a specific key and if found I change the value.
 If it is not found I add the entry.

 Kind regards
 André


 struct Data{
 	int key;
 	int value;
 }

 void main(){
 	Data[] entries = [Data(1,1),Data(2,2)];
 	bool found;

 	foreach(entry;entries){
 		if (entry.key == 3){
 			entry.value = 42;
 			found = true;
 		}
 	}

 	if (found == false){
 		entries ~= Data(3,42);
 	}
 }
Ranges in general don't work very well for modifying values in place. The Data structs are passed by value between functions, so any modifications made won't be reflected in the original array. Using ranges to modify values usually entails making a copy. You can still use std.algorithm to simplify the above code a bit, however: void main() { auto entries = [Data(1, 1), Data(2, 2)]; auto pos = entries.countUntil!(d => d.key == 3); if (pos >= 0) { entries[pos].value = 42; } else { entries ~= Data(3, 42); } writeln(entries); } Basically, just to abstract away the loop.
Jan 15 2014