www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - countUntil to print all the index of a given string.

reply Vino <vino.bheeman hotmail.com> writes:
Hi All,

   Request your help on printing the all index of an array element 
, eg; the below code prints the index of the string "Test2" as 
[1], but the string "Test2" is present 2 times at  index  1 and 
4, so how do I print all the index of a given string.

import std.stdio;
import std.container;
import std.algorithm;

void main () {
auto a = Array!string("Test1", "Test2", "Test3", "Test1", 
"Test2");
writeln(SList!int(a[].countUntil("Test2"))[]);
}

Output
[1]

Expected
[1, 4]

From,
Vino.B
Feb 18 2018
parent reply Cym13 <cpicard openmailbox.org> writes:
On Sunday, 18 February 2018 at 11:55:37 UTC, Vino wrote:
 Hi All,

   Request your help on printing the all index of an array 
 element , eg; the below code prints the index of the string 
 "Test2" as [1], but the string "Test2" is present 2 times at  
 index  1 and 4, so how do I print all the index of a given 
 string.

 import std.stdio;
 import std.container;
 import std.algorithm;

 void main () {
 auto a = Array!string("Test1", "Test2", "Test3", "Test1", 
 "Test2");
 writeln(SList!int(a[].countUntil("Test2"))[]);
 }

 Output
 [1]

 Expected
 [1, 4]

 From,
 Vino.B
countUntil is good when you want to avoid having to look at all your data, but in this case I don't think it's the best solution. You could do a loop storing each index and then restart your countUntil from there, but quite frankly it would be easier to just loop over the array at that point: ulong[] result; for (ulong index=0 ; index<a.length ; index++) if (a[index] == "Test2") result ~= index; writeln(result); You could also use enumerate to make this a tad easier: import std.range: enumerate; ulong[] result; foreach (index, value ; a[].enumerate) if (a[index] == "Test2") result ~= index; writeln(result); However, if you want a more streamlined, functionnal solution, you can go all the way and avoid all explicit loops and intermediate variables using fold: import std.range: enumerate; import std.algorithm: fold; a[] .enumerate .fold!((a, b) => b[1] == "Test2" ? a ~ b[0] : a)(cast(ulong[])[]) .writeln;
Feb 18 2018
parent reply Cym13 <cpicard openmailbox.org> writes:
On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
Feb 18 2018
next sibling parent psychoticRabbit <meagain meagain.com> writes:
On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
A nice example of how D's multiparadigm programming model allows the utilisation of algorithms that can scale to process massive datasets. There is an article in there somewhere ;-)
Feb 18 2018
prev sibling parent reply aberba <karabutaworld gmail.com> writes:
On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
How does one detect an operation as lazy or not? Is the some compile-time or runtime check for that? My guess is by referring to the docs function signature.
Feb 20 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, February 20, 2018 08:44:37 aberba via Digitalmars-d-learn wrote:
 On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
How does one detect an operation as lazy or not? Is the some compile-time or runtime check for that? My guess is by referring to the docs function signature.
You have to read the docs or read the source code, though in general, functions that return a range type that wraps the original range tend to be lazy, whereas if a function returns the original range type or an array, then it's clearly not lazy. - Jonathan M Davis
Feb 20 2018
parent Vino <vino.bheeman hotmail.com> writes:
On Tuesday, 20 February 2018 at 08:50:27 UTC, Jonathan M Davis 
wrote:
 On Tuesday, February 20, 2018 08:44:37 aberba via 
 Digitalmars-d-learn wrote:
 On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
How does one detect an operation as lazy or not? Is the some compile-time or runtime check for that? My guess is by referring to the docs function signature.
You have to read the docs or read the source code, though in general, functions that return a range type that wraps the original range tend to be lazy, whereas if a function returns the original range type or an array, then it's clearly not lazy. - Jonathan M Davis
Hi All, Thank you very much, the provide solution work's for the given example, so how can we achieve the same for the below code import std.stdio; import std.container; import std.algorithm; void main () { auto a = Array!string("Test1", "Test2", "Test3", "Test1", "Test2"); auto b = Array!string("Test1", "Test2", "Test3"); foreach(i; b[]) { writeln(SList!int(a[].countUntil(i))[]); } } Output [0] [1] [2] Required [0,3] [1,4] [2] From, Vino.B
Feb 24 2018
prev sibling parent reply Seb <seb wilzba.ch> writes:
On Tuesday, 20 February 2018 at 08:44:37 UTC, aberba wrote:
 On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
How does one detect an operation as lazy or not? Is the some compile-time or runtime check for that? My guess is by referring to the docs function signature.
While it's not a replacement for checking the code manually, nogc helps a lot: --- void main() nogc { import std.container, std.stdio; auto a = Array!string("Test1", "Test2", "Test3", "Test1", "Test2"); import std.algorithm, std.range; auto r = a[].enumerate.filter!(t => t[1] == "Test2").map!(t => t[0]); debug r.writeln; // std.stdio.writeln allocates at the moment } --- https://run.dlang.io/is/Fo32sN
Feb 24 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, February 25, 2018 01:49:05 Seb via Digitalmars-d-learn wrote:
 On Tuesday, 20 February 2018 at 08:44:37 UTC, aberba wrote:
 On Sunday, 18 February 2018 at 15:23:14 UTC, Cym13 wrote:
 On Sunday, 18 February 2018 at 14:48:59 UTC, Cym13 wrote:
 [...]
Just thought of a much better/simpler solution for that last case that also doesn't force you to read all data (which might be impossible when dealing with infinite ranges): import std.range; import std.algorithm; a[] .enumerate // get tuples (index, value) .filter!(t => t[1] == "Test2") // keep only if value == "Test2" .map!(t => t[0]) // keep only the index part .writeln; Completely lazy.
How does one detect an operation as lazy or not? Is the some compile-time or runtime check for that? My guess is by referring to the docs function signature.
While it's not a replacement for checking the code manually, nogc helps a lot:
That doesn't actually tell you whether the range is lazy. It just tells you whether any allocations may occur. If any exceptions could be thrown, then a lazy solution can't be nogc (something that's often the case with strings thanks to auto-decoding and UTFExceptions), and a solution could be eager without allocating if the result doesn't require any allocation. Also, you could have a lazy range that involves a lambda that allocates a closure. So, yeah, a lot of the time, nogc means that the range is lazy, but it doesn't guarantee it, and not being able to be nogc doesn't mean that it's eager. So, I'd argue that while nogc gives you a clue, it's ultimately a pretty poor way to try and figure out whether a range is lazy or not. All it really tells you is whether it's guaranteed that no allocations will occur on the GC heap. - Jonathan M Davis
Feb 24 2018
parent reply Seb <seb wilzba.ch> writes:
On Sunday, 25 February 2018 at 02:37:00 UTC, Jonathan M Davis 
wrote:
 If any exceptions could be thrown, then a lazy solution can't 
 be  nogc (something that's often the case with strings thanks 
 to auto-decoding and UTFExceptions), and a solution could be 
 eager without allocating if the result doesn't require any 
 allocation.
FYI -dip1008 is a thing now and part of 2.079. See also: https://dlang.org/changelog/pending.html#dip1008 https://run.dlang.io/is/clNX6G https://github.com/dlang/DIPs/blob/master/DIPs/DIP1008.md
 Also, you could have a lazy range that involves a lambda that 
 allocates a closure.
Of course, or a nogc range that allocates with malloc or eagerly steps through the entire range. Anyhow I just mentioned it because it's the best form of automatic checking that we have (what the OP was asking for) and in many cases when an algorithm can't be nogc it does allocate somewhere which is a red flag.
Feb 24 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, February 25, 2018 02:58:33 Seb via Digitalmars-d-learn wrote:
 On Sunday, 25 February 2018 at 02:37:00 UTC, Jonathan M Davis

 wrote:
 If any exceptions could be thrown, then a lazy solution can't
 be  nogc (something that's often the case with strings thanks
 to auto-decoding and UTFExceptions), and a solution could be
 eager without allocating if the result doesn't require any
 allocation.
FYI -dip1008 is a thing now and part of 2.079. See also: https://dlang.org/changelog/pending.html#dip1008 https://run.dlang.io/is/clNX6G https://github.com/dlang/DIPs/blob/master/DIPs/DIP1008.md
That will help eventually, but it requires a compiler flag, so it's really not going to help for code in general right now, and the fact that that DIP does nothing to solve the problem of how to create exception messages without allocating them on the GC heap means that exceptions in general are still frequently going to result in allocations unless you jump through several hoops to be able to create an exception message that's in a static array or malloc-ed or something. So, I don't know how much it's going to help in practice outside of code where the programmer is absolutely determined to have no GC allocations.
 Also, you could have a lazy range that involves a lambda that
 allocates a closure.
Of course, or a nogc range that allocates with malloc or eagerly steps through the entire range. Anyhow I just mentioned it because it's the best form of automatic checking that we have (what the OP was asking for) and in many cases when an algorithm can't be nogc it does allocate somewhere which is a red flag.
Yeah. There does tend to be a correlation between nogc and whether a range is lazy, but it's not guaranteed, so I'm inclined to think that it's a poor idea to rely on it and that it's just ultimately better to look at the documentation or even the code. - Jonathan M Davis
Feb 24 2018
parent reply Vino <vino.bheeman hotmail.com> writes:
On Sunday, 25 February 2018 at 03:41:27 UTC, Jonathan M Davis 
wrote:
 On Sunday, February 25, 2018 02:58:33 Seb via 
 Digitalmars-d-learn wrote:
 [...]
That will help eventually, but it requires a compiler flag, so it's really not going to help for code in general right now, and the fact that that DIP does nothing to solve the problem of how to create exception messages without allocating them on the GC heap means that exceptions in general are still frequently going to result in allocations unless you jump through several hoops to be able to create an exception message that's in a static array or malloc-ed or something. So, I don't know how much it's going to help in practice outside of code where the programmer is absolutely determined to have no GC allocations.
 [...]
Yeah. There does tend to be a correlation between nogc and whether a range is lazy, but it's not guaranteed, so I'm inclined to think that it's a poor idea to rely on it and that it's just ultimately better to look at the documentation or even the code. - Jonathan M Davis
Hi All, Sorry, I am not able to see any correlation between the raised topic and the conversation that is happening in this forum, could any one please explain on of what is going on and how do you thing that this conversation is related to the topic raised, if not would suggest you to open a new topic. From, Vino.B
Feb 25 2018
parent Andrew <aabrown24 hotmail.com> writes:
On Sunday, 25 February 2018 at 13:25:56 UTC, Vino wrote:
 On Sunday, 25 February 2018 at 03:41:27 UTC, Jonathan M Davis 
 wrote:
 On Sunday, February 25, 2018 02:58:33 Seb via 
 Digitalmars-d-learn wrote:
 [...]
That will help eventually, but it requires a compiler flag, so it's really not going to help for code in general right now, and the fact that that DIP does nothing to solve the problem of how to create exception messages without allocating them on the GC heap means that exceptions in general are still frequently going to result in allocations unless you jump through several hoops to be able to create an exception message that's in a static array or malloc-ed or something. So, I don't know how much it's going to help in practice outside of code where the programmer is absolutely determined to have no GC allocations.
 [...]
Yeah. There does tend to be a correlation between nogc and whether a range is lazy, but it's not guaranteed, so I'm inclined to think that it's a poor idea to rely on it and that it's just ultimately better to look at the documentation or even the code. - Jonathan M Davis
Hi All, Sorry, I am not able to see any correlation between the raised topic and the conversation that is happening in this forum, could any one please explain on of what is going on and how do you thing that this conversation is related to the topic raised, if not would suggest you to open a new topic. From, Vino.B
I think this will work: import std.container; import std.algorithm; import std.range; import std.stdio; void main () { auto a = Array!string("Test1", "Test2", "Test3", "Test1", "Test2"); auto b = Array!string("Test1", "Test2", "Test3"); foreach(i; b[]) a[].enumerate.filter!(a => a[1] == i).map!(a => a[0]).SList!size_t[].writeln;
Feb 25 2018