Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 18, 2018 countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
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 |
February 18, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vino | 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;
|
February 18, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Cym13 | 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.
|
February 19, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Cym13 | 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 ;-)
|
February 20, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Cym13 | 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.
|
February 20, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to aberba | 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
|
February 24, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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 |
February 25, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to aberba | 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 |
February 24, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Seb | 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
|
February 25, 2018 Re: countUntil to print all the index of a given string. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | 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. |
Copyright © 1999-2021 by the D Language Foundation