问:
Given a formattable string, is there a clean way to get the formatting string for the given arguments?
Suppose I had a FormattableString like so:

var now = DateTime.Now;
FormattableString str = $"Today's date is: {now:yyyy-MM-dd} and some numbers: {new[]{1,2,3}}";
```
<p>I'm trying to take a formattable string and transform it to be used in another component. In my case, essentially splitting the format string at the values so I can control how they're concatenated back, but I need the format string for the argument.</p>
<p>There are some limited methods on the <code>FormattableString</code> that allows me to get the argument values (<code>GetArguments()</code>/<code>GetArgument()</code>) and the original format string (<code>Format</code>), but there is none for accessing the argument formatting strings.</p>
<pre class="lang-cs prettyprint-override"><code>var format = str.Format; // "Today's date is: {0:yyyy-MM-dd} and some numbers: {1}"
var arguments = str.GetArguments(); // { now, new[]{1,2,3} }

// no simple way to get the "yyyy-MM-dd" part for arg 0
</code>```

My workarounds I'm looking at are to preformat the value so the formatted value is set as the argument or parsing out the format string which would not be ideal.

void DumpLine(FormattableString format)
{
    var values = format.GetArguments().Prepend(null);
    var parts = Regex.Split(format.Format, @"\{[^}]+\}");
    Util.HorizontalRun(false, values.Zip(parts).SelectMany(x => new[] { x.First, x.Second }).Skip(1)).Dump();
}

// usage
DumpLine($"Today's date is: {now.ToString("yyyy-MM-dd")} and some numbers: {new[]{1,2,3}}");
```
<p>Is this supported, perhaps through a helper class or am I out of luck?</p>
<hr />
<p>Thank you mariusz96 for pointing out the new InterpolatedStringHandler functionality. It does for me exactly what I needed it for. It's even flexible enough for me to add additional parameters should I need it in the future. This is what I ended up with:</p>
```public static class UtilEx
{
    public static object Interpolate(IFormatProvider provider, [InterpolatedStringHandlerArgument(nameof(provider))] InterpolateFormatHandler handler) => Interpolate(handler);
    public static object Interpolate(InterpolateFormatHandler handler) => Util.HorizontalRun(false, handler.Items);

    [InterpolatedStringHandler]
    public ref struct InterpolateFormatHandler
    {
        private readonly IFormatProvider? provider;
        public InterpolateFormatHandler(int _literalLength, int _formattedCount, IFormatProvider? provider = default) => this.provider = provider;
        public List<object?> Items { get; } = new();

        public void AppendLiteral(string s) => Items.Add(s);
        public void AppendFormatted<T>(T t, int alignment, string format) => Items.Add(string.Format(provider, $"{{0,{alignment}:{format}}}", t));
        public void AppendFormatted<T>(T t, int alignment) => Items.Add(string.Format(provider, $"{{0,{alignment}}}", t));
        public void AppendFormatted<T>(T t, string format) => Items.Add(string.Format(provider, $"{{0:{format}}}", t));
        public void AppendFormatted<T>(T t) => Items.Add(t);
    }
}
```

答:
none for accessing the argument formatting strings.. Is this supported, perhaps through a helper class or am I out of luck?

Interesting question. I'm tempted to say "no" - though I don't have any references/sources to cite I've always regarded FormattableString as a helper for interpolation that enables some parts of a program to know the difference between contexts where it receives a string, and contexts where it receives a formattable string - in essence, to know that something was once a string with format placeholders is helpful in cases like an SQL ORM running a raw command, and wanting to parameterize it. If it receives a FormattableString, it can parameterize the arguments and know where to insert them by parsing the format. If it straight received a formatted string it wouldn't be able to do that, so a FormattableString allows us to keep the format string and related arguments separated until the last moment.

When the compiler is turning an interpolated string into a formattable one, it has a relatively easy task. Take a look at what happens in this simple example, run through sharplab's compile/decompile cycle:

It's essentially just collecting variables mentioned inside a string, numbering them and swapping the interp out for a standard numerical placeholder format string. It doesn't need to touch the formatting specifiers when it converts {b:0000} -> {0:0000}

So the actual formats embedded in the placeholders aren't separated out at this stage; they're parsed out later. If we take a look at this internal method of a stringbuilder, which is what string.Format (eventually) defers to (which is what formattable string defers to), we can see it operating in statemachine parser style, hunting for non escaped {, parsing the numeric holder number, and then pulling the format and padding specifiers out by reference to commas and colons:

```<code>        //from .net framework reference source

        internal StringBuilder AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) {
            if (format == null) {
                throw new ArgumentNullException("format");
            }
            Contract.Ensures(Contract.Result<StringBuilder>() != null);
            Contract.EndContractBlock();

            int pos = 0;
            int len = format.Length;
            char ch = '\x0';

            ICustomFormatter cf = null;
            if (provider != null) {
                cf = (ICustomFormatter)provider.GetFormat(typeof(ICustomFormatter));
            }

            while (true) {
                int p = pos;
                int i = pos;
                while (pos < len) {
                    ch = format[pos];

                    pos++;
                    if (ch == '}')
                    {
                        if (pos < len && format[pos] == '}') // Treat as escape character for }}
                            pos++;
                        else
                            FormatError();
                    }

                    if (ch == '{')
                    {
                        if (pos < len && format[pos] == '{') // Treat as escape character for {{
                            pos++;
                        else
                        {
                            pos--;
                            break;
                        }
                    }

                    Append(ch);
                }

                if (pos == len) break;
                pos++;
                if (pos == len || (ch = format[pos]) < '0' || ch > '9') FormatError();
                int index = 0;
                do {
                    index = index * 10 + ch - '0';
                    pos++;
                    if (pos == len) FormatError();
                    ch = format[pos];
                } while (ch >= '0' && ch <= '9' && index < 1000000);
                if (index >= args.Length) throw new FormatException(Environment.GetResourceString("Format_IndexOutOfRange"));
                while (pos < len && (ch = format[pos]) == ' ') pos++;
                bool leftJustify = false;
                int width = 0;
                if (ch == ',') {
                    pos++;
                    while (pos < len && format[pos] == ' ') pos++;

                    if (pos == len) FormatError();
                    ch = format[pos];
                    if (ch == '-') {
                        leftJustify = true;
                        pos++;
                        if (pos == len) FormatError();
                        ch = format[pos];
                    }
                    if (ch < '0' || ch > '9') FormatError();
                    do {
                        width = width * 10 + ch - '0';
                        pos++;
                        if (pos == len) FormatError();
                        ch = format[pos];
                    } while (ch >= '0' && ch <= '9' && width < 1000000);
                }

                while (pos < len && (ch = format[pos]) == ' ') pos++;
                Object arg = args[index];
                StringBuilder fmt = null;
                if (ch == ':') {
                    pos++;
                    p = pos;
                    i = pos;
                    while (true) {
                        if (pos == len) FormatError();
                        ch = format[pos];
                        pos++;
                        if (ch == '{')
                        {
                            if (pos < len && format[pos] == '{')  // Treat as escape character for {{
                                pos++;
                            else
                                FormatError();
                        }
                        else if (ch == '}')
                        {
                            if (pos < len && format[pos] == '}')  // Treat as escape character for }}
                                pos++;
                            else
                            {
                                pos--;
                                break;
                            }
                        }

                        if (fmt == null) {
                            fmt = new StringBuilder();
                        }
                        fmt.Append(ch);
                    }
                }
                if (ch != '}') FormatError();
                pos++;
                String sFmt = null;
                String s = null;
                if (cf != null) {
                    if (fmt != null) {
                        sFmt = fmt.ToString();
                    }
                    s = cf.Format(sFmt, arg, provider);
                }

                if (s == null) {
                    IFormattable formattableArg = arg as IFormattable;

#if FEATURE_LEGACYNETCF
                    if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
                        // TimeSpan does not implement IFormattable in Mango
                        if(arg is TimeSpan) {
                            formattableArg = null;
                        }
                    }
#endif
                    if (formattableArg != null) {
                        if (sFmt == null && fmt != null) {
                            sFmt = fmt.ToString();
                        }

                        s = formattableArg.ToString(sFmt, provider);
                    } else if (arg != null) {
                        s = arg.ToString();
                    }
                }

                if (s == null) s = String.Empty;
                int pad = width - s.Length;
                if (!leftJustify && pad > 0) Append(' ', pad);
                Append(s);
                if (leftJustify && pad > 0) Append(' ', pad);
            }
            return this;
        }
</code>```

https://referencesource.microsoft.com/#mscorlib/system/text/stringbuilder.cs,2c3b4c2e7c43f5a4

All in, I'd say if you want those format arguments you'll need to pull them from the Format yourself; it's what the framework does. The code that does it is above, and could be tarted up/slimmed down but if you adopt the same approach with a helper as the framework does it should be similarly reliable and consistent in its behavior

ps; here's the source for the same method from .net core; essentially the same, but more nicely commented ;)

```<code>internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
        {
            if (format == null)
            {
                throw new ArgumentNullException(nameof(format));
            }

            int pos = 0;
            int len = format.Length;
            char ch = '\x0';

            ICustomFormatter? cf = null;
            if (provider != null)
            {
                cf = (ICustomFormatter?)provider.GetFormat(typeof(ICustomFormatter));
            }

            while (true)
            {
                while (pos < len)
                {
                    ch = format[pos];

                    pos++;
                    // Is it a closing brace?
                    if (ch == '}')
                    {
                        // Check next character (if there is one) to see if it is escaped. eg }}
                        if (pos < len && format[pos] == '}')
                        {
                            pos++;
                        }
                        else
                        {
                            // Otherwise treat it as an error (Mismatched closing brace)
                            FormatError();
                        }
                    }
                    // Is it an opening brace?
                    else if (ch == '{')
                    {
                        // Check next character (if there is one) to see if it is escaped. eg {{
                        if (pos < len && format[pos] == '{')
                        {
                            pos++;
                        }
                        else
                        {
                            // Otherwise treat it as the opening brace of an Argument Hole.
                            pos--;
                            break;
                        }
                    }
                    // If it's neither then treat the character as just text.
                    Append(ch);
                }

                //
                // Start of parsing of Argument Hole.
                // Argument Hole ::= { Index (, WS* Alignment WS*)? (: Formatting)? }
                //
                if (pos == len)
                {
                    break;
                }

                //
                //  Start of parsing required Index parameter.
                //  Index ::= ('0'-'9')+ WS*
                //
                pos++;
                // If reached end of text then error (Unexpected end of text)
                // or character is not a digit then error (Unexpected Character)
                if (pos == len || (ch = format[pos]) < '0' || ch > '9') FormatError();
                int index = 0;
                do
                {
                    index = index * 10 + ch - '0';
                    pos++;
                    // If reached end of text then error (Unexpected end of text)
                    if (pos == len)
                    {
                        FormatError();
                    }
                    ch = format[pos];
                    // so long as character is digit and value of the index is less than 1000000 ( index limit )
                }
                while (ch >= '0' && ch <= '9' && index < IndexLimit);

                // If value of index is not within the range of the arguments passed in then error (Index out of range)
                if (index >= args.Length)
                {
                    throw new FormatException(SR.Format_IndexOutOfRange);
                }

                // Consume optional whitespace.
                while (pos < len && (ch = format[pos]) == ' ') pos++;
                // End of parsing index parameter.

                //
                //  Start of parsing of optional Alignment
                //  Alignment ::= comma WS* minus? ('0'-'9')+ WS*
                //
                bool leftJustify = false;
                int width = 0;
                // Is the character a comma, which indicates the start of alignment parameter.
                if (ch == ',')
                {
                    pos++;

                    // Consume Optional whitespace
                    while (pos < len && format[pos] == ' ') pos++;

                    // If reached the end of the text then error (Unexpected end of text)
                    if (pos == len)
                    {
                        FormatError();
                    }

                    // Is there a minus sign?
                    ch = format[pos];
                    if (ch == '-')
                    {
                        // Yes, then alignment is left justified.
                        leftJustify = true;
                        pos++;
                        // If reached end of text then error (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];
                    }

                    // If current character is not a digit then error (Unexpected character)
                    if (ch < '0' || ch > '9')
                    {
                        FormatError();
                    }
                    // Parse alignment digits.
                    do
                    {
                        width = width * 10 + ch - '0';
                        pos++;
                        // If reached end of text then error. (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];
                        // So long a current character is a digit and the value of width is less than 100000 ( width limit )
                    }
                    while (ch >= '0' && ch <= '9' && width < WidthLimit);
                    // end of parsing Argument Alignment
                }

                // Consume optional whitespace
                while (pos < len && (ch = format[pos]) == ' ') pos++;

                //
                // Start of parsing of optional formatting parameter.
                //
                object? arg = args[index];

                ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
                // Is current character a colon? which indicates start of formatting parameter.
                if (ch == ':')
                {
                    pos++;
                    int startPos = pos;

                    while (true)
                    {
                        // If reached end of text then error. (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];

                        if (ch == '}')
                        {
                            // Argument hole closed
                            break;
                        }
                        else if (ch == '{')
                        {
                            // Braces inside the argument hole are not supported
                            FormatError();
                        }

                        pos++;
                    }

                    if (pos > startPos)
                    {
                        itemFormatSpan = format.AsSpan(startPos, pos - startPos);
                    }
                }
                else if (ch != '}')
                {
                    // Unexpected character
                    FormatError();
                }

                // Construct the output for this arg hole.
                pos++;
                string? s = null;
                string? itemFormat = null;

                if (cf != null)
                {
                    if (itemFormatSpan.Length != 0)
                    {
                        itemFormat = new string(itemFormatSpan);
                    }
                    s = cf.Format(itemFormat, arg, provider);
                }

                if (s == null)
                {
                    // If arg is ISpanFormattable and the beginning doesn't need padding,
                    // try formatting it into the remaining current chunk.
                    if (arg is ISpanFormattable spanFormattableArg &&
                        (leftJustify || width == 0) &&
                        spanFormattableArg.TryFormat(RemainingCurrentChunk, out int charsWritten, itemFormatSpan, provider))
                    {
                        if ((uint)charsWritten > (uint)RemainingCurrentChunk.Length)
                        {
                            // Untrusted ISpanFormattable implementations might return an erroneous charsWritten value,
                            // and m_ChunkLength might end up being used in Unsafe code, so fail if we get back an
                            // out-of-range charsWritten value.
                            FormatError();
                        }

                        m_ChunkLength += charsWritten;

                        // Pad the end, if needed.
                        int padding = width - charsWritten;
                        if (leftJustify && padding > 0)
                        {
                            Append(' ', padding);
                        }

                        // Continue to parse other characters.
                        continue;
                    }

                    // Otherwise, fallback to trying IFormattable or calling ToString.
                    if (arg is IFormattable formattableArg)
                    {
                        if (itemFormatSpan.Length != 0)
                        {
                            itemFormat ??= new string(itemFormatSpan);
                        }
                        s = formattableArg.ToString(itemFormat, provider);
                    }
                    else if (arg != null)
                    {
                        s = arg.ToString();
                    }
                }
                // Append it to the final output of the Format String.
                if (s == null)
                {
                    s = string.Empty;
                }
                int pad = width - s.Length;
                if (!leftJustify && pad > 0)
                {
                    Append(' ', pad);
                }

                Append(s);
                if (leftJustify && pad > 0)
                {
                    Append(' ', pad);
                }
                // Continue to parse other characters.
            }
            return this;
        }
</code>```

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs

Body:
Suppose I had a FormattableString like so:

var now = DateTime.Now;
FormattableString str = $"Today's date is: {now:yyyy-MM-dd} and some numbers: {new[]{1,2,3}}";

I'm trying to take a formattable string and transform it to be used in another component. In my case, essentially splitting the format string at the values so I can control how they're concatenated back, but I need the format string for the argument.

There are some limited methods on the FormattableString that allows me to get the argument values (GetArguments()/GetArgument()) and the original format string (Format), but there is none for accessing the argument formatting strings.

var format = str.Format; // "Today's date is: {0:yyyy-MM-dd} and some numbers: {1}"
var arguments = str.GetArguments(); // { now, new[]{1,2,3} }

// no simple way to get the "yyyy-MM-dd" part for arg 0

My workarounds I'm looking at are to preformat the value so the formatted value is set as the argument or parsing out the format string which would not be ideal.

void DumpLine(FormattableString format)
{
    var values = format.GetArguments().Prepend(null);
    var parts = Regex.Split(format.Format, @"\{[^}]+\}");
    Util.HorizontalRun(false, values.Zip(parts).SelectMany(x => new[] { x.First, x.Second }).Skip(1)).Dump();
}

// usage
DumpLine($"Today's date is: {now.ToString("yyyy-MM-dd")} and some numbers: {new[]{1,2,3}}");

Is this supported, perhaps through a helper class or am I out of luck?

Thank you mariusz96 for pointing out the new InterpolatedStringHandler functionality. It does for me exactly what I needed it for. It's even flexible enough for me to add additional parameters should I need it in the future. This is what I ended up with:

public static class UtilEx
{
    public static object Interpolate(IFormatProvider provider, [InterpolatedStringHandlerArgument(nameof(provider))] InterpolateFormatHandler handler) => Interpolate(handler);
    public static object Interpolate(InterpolateFormatHandler handler) => Util.HorizontalRun(false, handler.Items);

    [InterpolatedStringHandler]
    public ref struct InterpolateFormatHandler
    {
        private readonly IFormatProvider? provider;
        public InterpolateFormatHandler(int _literalLength, int _formattedCount, IFormatProvider? provider = default) => this.provider = provider;
        public List<object?> Items { get; } = new();

        public void AppendLiteral(string s) => Items.Add(s);
        public void AppendFormatted<T>(T t, int alignment, string format) => Items.Add(string.Format(provider, $"{{0,{alignment}:{format}}}", t));
        public void AppendFormatted<T>(T t, int alignment) => Items.Add(string.Format(provider, $"{{0,{alignment}}}", t));
        public void AppendFormatted<T>(T t, string format) => Items.Add(string.Format(provider, $"{{0:{format}}}", t));
        public void AppendFormatted<T>(T t) => Items.Add(t);
    }
}

Body:
none for accessing the argument formatting strings.. Is this supported, perhaps through a helper class or am I out of luck?

Interesting question. I'm tempted to say "no" - though I don't have any references/sources to cite I've always regarded FormattableString as a helper for interpolation that enables some parts of a program to know the difference between contexts where it receives a string, and contexts where it receives a formattable string - in essence, to know that something was once a string with format placeholders is helpful in cases like an SQL ORM running a raw command, and wanting to parameterize it. If it receives a FormattableString, it can parameterize the arguments and know where to insert them by parsing the format. If it straight received a formatted string it wouldn't be able to do that, so a FormattableString allows us to keep the format string and related arguments separated until the last moment.

When the compiler is turning an interpolated string into a formattable one, it has a relatively easy task. Take a look at what happens in this simple example, run through sharplab's compile/decompile cycle:

It's essentially just collecting variables mentioned inside a string, numbering them and swapping the interp out for a standard numerical placeholder format string. It doesn't need to touch the formatting specifiers when it converts {b:0000} -> {0:0000}

So the actual formats embedded in the placeholders aren't separated out at this stage; they're parsed out later. If we take a look at this internal method of a stringbuilder, which is what string.Format (eventually) defers to (which is what formattable string defers to), we can see it operating in statemachine parser style, hunting for non escaped {, parsing the numeric holder number, and then pulling the format and padding specifiers out by reference to commas and colons:

        //from .net framework reference source

        internal StringBuilder AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) {
            if (format == null) {
                throw new ArgumentNullException("format");
            }
            Contract.Ensures(Contract.Result<StringBuilder>() != null);
            Contract.EndContractBlock();

            int pos = 0;
            int len = format.Length;
            char ch = '\x0';

            ICustomFormatter cf = null;
            if (provider != null) {
                cf = (ICustomFormatter)provider.GetFormat(typeof(ICustomFormatter));
            }

            while (true) {
                int p = pos;
                int i = pos;
                while (pos < len) {
                    ch = format[pos];

                    pos++;
                    if (ch == '}')
                    {
                        if (pos < len && format[pos] == '}') // Treat as escape character for }}
                            pos++;
                        else
                            FormatError();
                    }

                    if (ch == '{')
                    {
                        if (pos < len && format[pos] == '{') // Treat as escape character for {{
                            pos++;
                        else
                        {
                            pos--;
                            break;
                        }
                    }

                    Append(ch);
                }

                if (pos == len) break;
                pos++;
                if (pos == len || (ch = format[pos]) < '0' || ch > '9') FormatError();
                int index = 0;
                do {
                    index = index * 10 + ch - '0';
                    pos++;
                    if (pos == len) FormatError();
                    ch = format[pos];
                } while (ch >= '0' && ch <= '9' && index < 1000000);
                if (index >= args.Length) throw new FormatException(Environment.GetResourceString("Format_IndexOutOfRange"));
                while (pos < len && (ch = format[pos]) == ' ') pos++;
                bool leftJustify = false;
                int width = 0;
                if (ch == ',') {
                    pos++;
                    while (pos < len && format[pos] == ' ') pos++;

                    if (pos == len) FormatError();
                    ch = format[pos];
                    if (ch == '-') {
                        leftJustify = true;
                        pos++;
                        if (pos == len) FormatError();
                        ch = format[pos];
                    }
                    if (ch < '0' || ch > '9') FormatError();
                    do {
                        width = width * 10 + ch - '0';
                        pos++;
                        if (pos == len) FormatError();
                        ch = format[pos];
                    } while (ch >= '0' && ch <= '9' && width < 1000000);
                }

                while (pos < len && (ch = format[pos]) == ' ') pos++;
                Object arg = args[index];
                StringBuilder fmt = null;
                if (ch == ':') {
                    pos++;
                    p = pos;
                    i = pos;
                    while (true) {
                        if (pos == len) FormatError();
                        ch = format[pos];
                        pos++;
                        if (ch == '{')
                        {
                            if (pos < len && format[pos] == '{')  // Treat as escape character for {{
                                pos++;
                            else
                                FormatError();
                        }
                        else if (ch == '}')
                        {
                            if (pos < len && format[pos] == '}')  // Treat as escape character for }}
                                pos++;
                            else
                            {
                                pos--;
                                break;
                            }
                        }

                        if (fmt == null) {
                            fmt = new StringBuilder();
                        }
                        fmt.Append(ch);
                    }
                }
                if (ch != '}') FormatError();
                pos++;
                String sFmt = null;
                String s = null;
                if (cf != null) {
                    if (fmt != null) {
                        sFmt = fmt.ToString();
                    }
                    s = cf.Format(sFmt, arg, provider);
                }

                if (s == null) {
                    IFormattable formattableArg = arg as IFormattable;

#if FEATURE_LEGACYNETCF
                    if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
                        // TimeSpan does not implement IFormattable in Mango
                        if(arg is TimeSpan) {
                            formattableArg = null;
                        }
                    }
#endif
                    if (formattableArg != null) {
                        if (sFmt == null && fmt != null) {
                            sFmt = fmt.ToString();
                        }

                        s = formattableArg.ToString(sFmt, provider);
                    } else if (arg != null) {
                        s = arg.ToString();
                    }
                }

                if (s == null) s = String.Empty;
                int pad = width - s.Length;
                if (!leftJustify && pad > 0) Append(' ', pad);
                Append(s);
                if (leftJustify && pad > 0) Append(' ', pad);
            }
            return this;
        }

https://referencesource.microsoft.com/#mscorlib/system/text/stringbuilder.cs,2c3b4c2e7c43f5a4

All in, I'd say if you want those format arguments you'll need to pull them from the Format yourself; it's what the framework does. The code that does it is above, and could be tarted up/slimmed down but if you adopt the same approach with a helper as the framework does it should be similarly reliable and consistent in its behavior

ps; here's the source for the same method from .net core; essentially the same, but more nicely commented ;)

internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
        {
            if (format == null)
            {
                throw new ArgumentNullException(nameof(format));
            }

            int pos = 0;
            int len = format.Length;
            char ch = '\x0';

            ICustomFormatter? cf = null;
            if (provider != null)
            {
                cf = (ICustomFormatter?)provider.GetFormat(typeof(ICustomFormatter));
            }

            while (true)
            {
                while (pos < len)
                {
                    ch = format[pos];

                    pos++;
                    // Is it a closing brace?
                    if (ch == '}')
                    {
                        // Check next character (if there is one) to see if it is escaped. eg }}
                        if (pos < len && format[pos] == '}')
                        {
                            pos++;
                        }
                        else
                        {
                            // Otherwise treat it as an error (Mismatched closing brace)
                            FormatError();
                        }
                    }
                    // Is it an opening brace?
                    else if (ch == '{')
                    {
                        // Check next character (if there is one) to see if it is escaped. eg {{
                        if (pos < len && format[pos] == '{')
                        {
                            pos++;
                        }
                        else
                        {
                            // Otherwise treat it as the opening brace of an Argument Hole.
                            pos--;
                            break;
                        }
                    }
                    // If it's neither then treat the character as just text.
                    Append(ch);
                }

                //
                // Start of parsing of Argument Hole.
                // Argument Hole ::= { Index (, WS* Alignment WS*)? (: Formatting)? }
                //
                if (pos == len)
                {
                    break;
                }

                //
                //  Start of parsing required Index parameter.
                //  Index ::= ('0'-'9')+ WS*
                //
                pos++;
                // If reached end of text then error (Unexpected end of text)
                // or character is not a digit then error (Unexpected Character)
                if (pos == len || (ch = format[pos]) < '0' || ch > '9') FormatError();
                int index = 0;
                do
                {
                    index = index * 10 + ch - '0';
                    pos++;
                    // If reached end of text then error (Unexpected end of text)
                    if (pos == len)
                    {
                        FormatError();
                    }
                    ch = format[pos];
                    // so long as character is digit and value of the index is less than 1000000 ( index limit )
                }
                while (ch >= '0' && ch <= '9' && index < IndexLimit);

                // If value of index is not within the range of the arguments passed in then error (Index out of range)
                if (index >= args.Length)
                {
                    throw new FormatException(SR.Format_IndexOutOfRange);
                }

                // Consume optional whitespace.
                while (pos < len && (ch = format[pos]) == ' ') pos++;
                // End of parsing index parameter.

                //
                //  Start of parsing of optional Alignment
                //  Alignment ::= comma WS* minus? ('0'-'9')+ WS*
                //
                bool leftJustify = false;
                int width = 0;
                // Is the character a comma, which indicates the start of alignment parameter.
                if (ch == ',')
                {
                    pos++;

                    // Consume Optional whitespace
                    while (pos < len && format[pos] == ' ') pos++;

                    // If reached the end of the text then error (Unexpected end of text)
                    if (pos == len)
                    {
                        FormatError();
                    }

                    // Is there a minus sign?
                    ch = format[pos];
                    if (ch == '-')
                    {
                        // Yes, then alignment is left justified.
                        leftJustify = true;
                        pos++;
                        // If reached end of text then error (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];
                    }

                    // If current character is not a digit then error (Unexpected character)
                    if (ch < '0' || ch > '9')
                    {
                        FormatError();
                    }
                    // Parse alignment digits.
                    do
                    {
                        width = width * 10 + ch - '0';
                        pos++;
                        // If reached end of text then error. (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];
                        // So long a current character is a digit and the value of width is less than 100000 ( width limit )
                    }
                    while (ch >= '0' && ch <= '9' && width < WidthLimit);
                    // end of parsing Argument Alignment
                }

                // Consume optional whitespace
                while (pos < len && (ch = format[pos]) == ' ') pos++;

                //
                // Start of parsing of optional formatting parameter.
                //
                object? arg = args[index];

                ReadOnlySpan<char> itemFormatSpan = default; // used if itemFormat is null
                // Is current character a colon? which indicates start of formatting parameter.
                if (ch == ':')
                {
                    pos++;
                    int startPos = pos;

                    while (true)
                    {
                        // If reached end of text then error. (Unexpected end of text)
                        if (pos == len)
                        {
                            FormatError();
                        }
                        ch = format[pos];

                        if (ch == '}')
                        {
                            // Argument hole closed
                            break;
                        }
                        else if (ch == '{')
                        {
                            // Braces inside the argument hole are not supported
                            FormatError();
                        }

                        pos++;
                    }

                    if (pos > startPos)
                    {
                        itemFormatSpan = format.AsSpan(startPos, pos - startPos);
                    }
                }
                else if (ch != '}')
                {
                    // Unexpected character
                    FormatError();
                }

                // Construct the output for this arg hole.
                pos++;
                string? s = null;
                string? itemFormat = null;

                if (cf != null)
                {
                    if (itemFormatSpan.Length != 0)
                    {
                        itemFormat = new string(itemFormatSpan);
                    }
                    s = cf.Format(itemFormat, arg, provider);
                }

                if (s == null)
                {
                    // If arg is ISpanFormattable and the beginning doesn't need padding,
                    // try formatting it into the remaining current chunk.
                    if (arg is ISpanFormattable spanFormattableArg &&
                        (leftJustify || width == 0) &&
                        spanFormattableArg.TryFormat(RemainingCurrentChunk, out int charsWritten, itemFormatSpan, provider))
                    {
                        if ((uint)charsWritten > (uint)RemainingCurrentChunk.Length)
                        {
                            // Untrusted ISpanFormattable implementations might return an erroneous charsWritten value,
                            // and m_ChunkLength might end up being used in Unsafe code, so fail if we get back an
                            // out-of-range charsWritten value.
                            FormatError();
                        }

                        m_ChunkLength += charsWritten;

                        // Pad the end, if needed.
                        int padding = width - charsWritten;
                        if (leftJustify && padding > 0)
                        {
                            Append(' ', padding);
                        }

                        // Continue to parse other characters.
                        continue;
                    }

                    // Otherwise, fallback to trying IFormattable or calling ToString.
                    if (arg is IFormattable formattableArg)
                    {
                        if (itemFormatSpan.Length != 0)
                        {
                            itemFormat ??= new string(itemFormatSpan);
                        }
                        s = formattableArg.ToString(itemFormat, provider);
                    }
                    else if (arg != null)
                    {
                        s = arg.ToString();
                    }
                }
                // Append it to the final output of the Format String.
                if (s == null)
                {
                    s = string.Empty;
                }
                int pad = width - s.Length;
                if (!leftJustify && pad > 0)
                {
                    Append(' ', pad);
                }

                Append(s);
                if (leftJustify && pad > 0)
                {
                    Append(' ', pad);
                }
                // Continue to parse other characters.
            }
            return this;
        }

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs


来源: stackexchange

问:
how scanf with character class work without format specifier
```<code>char info[30];
scanf("%79[^\n]", info);
printf("%s", info);
</code>```

This code works successfully. But

```<code>scanf("%79", info);
</code>```

will not work. I need to modify it like that:

```<code>scanf("%79s", info);
</code>```

I understand that first code snippet means read till newline. But how does it work without "s" format specifier?

答:
how does it work without "s" format specifier?

It works because it's a completely different format specifier.  It has nothing to do with %s.

Most scanf format specifiers are based on a single letter, perhaps along with some modifier letters, like %d, or %f, or %lf.

But %[…] is different: it's got a [, and a set of characters to scan, and a ].  The complete specifier ends at the ].

All scanf format specifiers take an optional "width" specifier between the % and the other stuff.  So %79s is a length-limited version of %s, and "%79[^\n]" is a length-limited version of %[…].

You will sometimes see people write things like "%[^\n]s", as if [^\n] is some kind of modifier that modifies %s.  But it's not; that s at the end of "%[^\n]s" is in error.

ContentLicense: CC BY-SA 4.0

Body:
char info[30];
scanf("%79[^\n]", info);
printf("%s", info);

This code works successfully. But

scanf("%79", info);

will not work. I need to modify it like that:

scanf("%79s", info);

I understand that first code snippet means read till newline. But how does it work without "s" format specifier?


问:
How to estimate count for Pandas dataframe column values based on multiple conditions?
Given a pandas DataFrame df of the following format:-

```<code>StudyNo   Condition1      Condition2      ResultVal
1222          25              30              0.5
1245          30              45              0.12
1672          40              15              0.46
1222          25              30              0.95
1245          30              45              0.88
1245          30              45              0.23
</code>```

I would like to calculate frequency/count of the number of ResultVal attributes existing in the dataset for a specific StudyNo under a given Condition1 and Condition2. There are no exactly duplicate rows in this dataset.

e.g. for StudyNo 1245 at Condition1 of 30 and Condition2 of 45, the count would be 3 (because 3 ResultVal attributes exist for this aspect). Also, I would like to print out a list of StudyNo, Condition1 and Condition2 in cases wherein < =1 ResultVal attributes exist (which in this example would be [1672,40,15].

Any help in this regard would be much appreciated.

答:
You can groupby "StudyNo", "Condition1" and "Condition2" and transform count of "ResultVal" to create column "Frequency".

Then create a boolean mask for rows where "Frequency" is less than or equal to 1 and filter the rows that satisfy it.

```<code>cols = ['StudyNo','Condition1','Condition2']
df['Frequency'] = df.groupby(cols)['ResultVal'].transform('count')
appears_only_once = df.loc[df['Frequency'] <= 1, cols].to_numpy().tolist()
</code>```

Output:

```<code>   StudyNo  Condition1  Condition2  ResultVal  Frequency
0     1222          25          30       0.50          2
1     1245          30          45       0.12          3
2     1672          40          15       0.46          1
3     1222          25          30       0.95          2
4     1245          30          45       0.88          3
5     1245          30          45       0.23          3
</code>```

The list:

```<code>[[1672, 40, 15]]
</code>```

Body:
Given a pandas DataFrame df of the following format:-

StudyNo   Condition1      Condition2      ResultVal
1222          25              30              0.5
1245          30              45              0.12
1672          40              15              0.46
1222          25              30              0.95
1245          30              45              0.88
1245          30              45              0.23

I would like to calculate frequency/count of the number of ResultVal attributes existing in the dataset for a specific StudyNo under a given Condition1 and Condition2. There are no exactly duplicate rows in this dataset.

e.g. for StudyNo 1245 at Condition1 of 30 and Condition2 of 45, the count would be 3 (because 3 ResultVal attributes exist for this aspect). Also, I would like to print out a list of StudyNo, Condition1 and Condition2 in cases wherein < =1 ResultVal attributes exist (which in this example would be [1672,40,15].

Any help in this regard would be much appreciated.

Body:
You can groupby "StudyNo", "Condition1" and "Condition2" and transform count of "ResultVal" to create column "Frequency".

Then create a boolean mask for rows where "Frequency" is less than or equal to 1 and filter the rows that satisfy it.

cols = ['StudyNo','Condition1','Condition2']
df['Frequency'] = df.groupby(cols)['ResultVal'].transform('count')
appears_only_once = df.loc[df['Frequency'] <= 1, cols].to_numpy().tolist()

Output:

   StudyNo  Condition1  Condition2  ResultVal  Frequency
0     1222          25          30       0.50          2
1     1245          30          45       0.12          3
2     1672          40          15       0.46          1
3     1222          25          30       0.95          2
4     1245          30          45       0.88          3
5     1245          30          45       0.23          3

The list:

[[1672, 40, 15]]


问:
how do I call my functions in .net
I am learning .net and writing a service by following the tutorial below http://www.beansoftware.com/NET-Tutorials/Create-Windows-Services.aspx

The windows service gets installed successfully and it starts too. But when I change the file name or delete a file or add a file, it doesnt add any information to my log file which is in
C:\Folder\FolderLog.txt

I see 3 methods for FolderWatcher_** but I dont see a call to those in the code. I am very new to .net so I am not sure how they are being called

here is my complete code

```<code>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;

    namespace Watcher
    {
        public partial class Watcher : ServiceBase
        {
            public Watcher()
            {
                InitializeComponent();
            }

            protected override void OnStart(string[] args)
            {

            }

            protected override void OnStop()
            {
            }

            private void FolderWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\FolderLog.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been created. ");
                writer.Close();
            }

            private void FolderWatcher_Deleted(object sender, System.IO.FileSystemEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\FolderLog.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been deleted. ");
                writer.Close();
            }

            private void FolderWatcher_Renamed(object sender, System.IO.RenamedEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\log.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been renamed. ");
                writer.Close();
            }

        }
    }
</code>```

I have followed every single step in that tutorial. I have not seen anything that descibes how these methods are called. Any help would be great

答:
Make sure you register the events of the watcher instance "FolderWatcher" to the events handlers in your code, you can do that at service designer or in the constructor of the service, like:

```<code>public Watcher()
{
    InitializeComponent();

    FolderWatcher.Created += FolderWatcher_Created;//when created FolderWatcher_Created will be called
    FolderWatcher.Deleted += FolderWatcher_Deleted;//when deleted call FolderWatcher_Deleted will be called
    FolderWatcher.Renamed += FolderWatcher_Renamed;//when renamed FolderWatcher_Renamed will be called
}
</code>```

ContentLicense: CC BY-SA 3.0

Title: how do I call my functions in .net

Body:
I am learning .net and writing a service by following the tutorial below http://www.beansoftware.com/NET-Tutorials/Create-Windows-Services.aspx

The windows service gets installed successfully and it starts too. But when I change the file name or delete a file or add a file, it doesnt add any information to my log file which is in
C:\Folder\FolderLog.txt

I see 3 methods for FolderWatcher_** but I dont see a call to those in the code. I am very new to .net so I am not sure how they are being called

here is my complete code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;

    namespace Watcher
    {
        public partial class Watcher : ServiceBase
        {
            public Watcher()
            {
                InitializeComponent();
            }

            protected override void OnStart(string[] args)
            {

            }

            protected override void OnStop()
            {
            }

            private void FolderWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\FolderLog.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been created. ");
                writer.Close();
            }

            private void FolderWatcher_Deleted(object sender, System.IO.FileSystemEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\FolderLog.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been deleted. ");
                writer.Close();
            }

            private void FolderWatcher_Renamed(object sender, System.IO.RenamedEventArgs e)
            {
                TextWriter writer = new StreamWriter("C:\\folder\\log.txt", true);
                writer.WriteLine(DateTime.Now + " A new folder/file with name " + e.Name + " has been renamed. ");
                writer.Close();
            }

        }
    }

I have followed every single step in that tutorial. I have not seen anything that descibes how these methods are called. Any help would be great

Body:
Make sure you register the events of the watcher instance "FolderWatcher" to the events handlers in your code, you can do that at service designer or in the constructor of the service, like:

public Watcher()
{
    InitializeComponent();

    FolderWatcher.Created += FolderWatcher_Created;//when created FolderWatcher_Created will be called
    FolderWatcher.Deleted += FolderWatcher_Deleted;//when deleted call FolderWatcher_Deleted will be called
    FolderWatcher.Renamed += FolderWatcher_Renamed;//when renamed FolderWatcher_Renamed will be called
}


问:
Simplify chained expression in ANTLR listener
I have an ANTLR listener for C++ where I want to get the name of a member declarator. Currently, I'm using this approach:

def enterMemberDeclarator(self, ctx: CPP14Parser.MemberDeclaratorContext):
    id = ctx.declarator().pointerDeclarator().noPointerDeclarator().noPointerDeclarator().declaratorid().idExpression().unqualifiedId()
```

which is just a horrible expression. I feel like there should be some way of getting the id immediately without having to go down that rabbit hole. Additionally, some of these expressions might be None so I fear that I would have to make even more effort to get to the result...

The grammar is from here

答:
This definitely looks very brittle (specific to a particular example).

You might consider a recursive method that checks the type of the context being passed in and chooses the appropriate attribute.

I'm not a Python programmer, so (in pseudoCode) something like the following:

```<code>function getMDName(ctx: <appropriate ANTLR base class) -> String
  if ctx is MemberDeclarationContext
    return getMDName(ctx.declarator()

  if ctx is DeclaratorContext
    if ctx.pointerDeclarator() != null
      return getMDName(ctx.pointerDeclarator())
    else
      return getMDName(ctx.noPointerDeclarator())

  if ctx is NoPointerDeclaratorContext
    if ctx.declaratorid() != null
      return getMDName(ctx.declaratorid())
    else if ctx.pointerDeclarator() != null
      return getMDName(ctx.pointerDeclaration())
    else
      return getMDNAME(ctx.noPointerDeclarator())

  if ctx is PointerDeclarationContext
    return getMDName(ctx.noPointerDeclaration())

  if ctx is declaratorIdContext
    return getMDName(ctx.idExpression()..unqualifiedId()

}
</code>```

Body:
I have an ANTLR listener for C++ where I want to get the name of a member declarator. Currently, I'm using this approach:

def enterMemberDeclarator(self, ctx: CPP14Parser.MemberDeclaratorContext):
    id = ctx.declarator().pointerDeclarator().noPointerDeclarator().noPointerDeclarator().declaratorid().idExpression().unqualifiedId()

which is just a horrible expression. I feel like there should be some way of getting the id immediately without having to go down that rabbit hole. Additionally, some of these expressions might be None so I fear that I would have to make even more effort to get to the result...

The grammar is from here

Body:
This definitely looks very brittle (specific to a particular example).

You might consider a recursive method that checks the type of the context being passed in and chooses the appropriate attribute.

I'm not a Python programmer, so (in pseudoCode) something like the following:

function getMDName(ctx: <appropriate ANTLR base class) -> String
  if ctx is MemberDeclarationContext
    return getMDName(ctx.declarator()

  if ctx is DeclaratorContext
    if ctx.pointerDeclarator() != null
      return getMDName(ctx.pointerDeclarator())
    else
      return getMDName(ctx.noPointerDeclarator())

  if ctx is NoPointerDeclaratorContext
    if ctx.declaratorid() != null
      return getMDName(ctx.declaratorid())
    else if ctx.pointerDeclarator() != null
      return getMDName(ctx.pointerDeclaration())
    else
      return getMDNAME(ctx.noPointerDeclarator())

  if ctx is PointerDeclarationContext
    return getMDName(ctx.noPointerDeclaration())

  if ctx is declaratorIdContext
    return getMDName(ctx.idExpression()..unqualifiedId()

}


问:
MariaDB vs PostgreSQL INSERT - PostgreSQL 2-4 times faster
I'm comparing MariaDB 10.6 vs PostgreSQL 14 in INSERT operation.
I created a table in both databases, then I tried to insert 1 Million rows in both.
In PostgreSQL, it takes only 2 seconds to INSERT 1 million rows.
But in MariaDB, it takes 9 seconds to INSERT 1 million rows.
But I want to work with MariaDB, so I tried to improve the my.ini but still PostgreSQL is about 2-4 times faster than MariaDB.
This is my table in both databases (no index in both, except the primary key with autoincrement)

```<code>CREATE TABLE `project_user` (
    `user_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_username` VARCHAR(16) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_mobile` VARCHAR(16) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_email` VARCHAR(64) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_first_name` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_first_name_en` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_last_name` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_last_name_en` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_country` TINYINT(3) UNSIGNED NULL DEFAULT NULL,
    `user_gender` BIT(1) NULL DEFAULT NULL,
    `user_registered_ip` INT(10) UNSIGNED NOT NULL,
    `user_registered_at` INT(10) UNSIGNED NOT NULL,
    `user_status` BIT(1) NOT NULL DEFAULT b'1',
    PRIMARY KEY (`user_id`) USING BTREE
)
COLLATE='ascii_general_ci'
ENGINE=InnoDB
;
</code>```

in PostgreSQL is equal to this table too (except the tinyint which i used bit) ...

In PostgreSQL, I used this operation to insert 1 million rows

```<code>INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT i,i+1
FROM generate_series(1, 1000000) AS i;
</code>```

And in MariaDB I used this function

```<code>BEGIN
    FOR i IN 1..1000000
    DO
        INSERT INTO `project_user` (`user_registered_ip`,`user_registered_at`)
        VALUES (i, i+1);
    END FOR;
    RETURN 1;
END
</code>```

And this is my.ini

```<code>[mysqld]
datadir=C:/Program Files/MariaDB 10.6/data
port=3306
max_connections=8192
max_allowed_packet=1G
skip_external_locking
skip_name_resolve
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_buffer_pool_size=24G
innodb_buffer_pool_instances=24
innodb_flush_log_at_trx_commit=0
innodb_flush_method=O_DIRECT
innodb_log_buffer_size=8M
innodb_log_file_size=2G
innodb_sort_buffer_size=16M
innodb_stats_on_metadata=0
innodb_thread_concurrency=6
innodb_read_io_threads=64
innodb_write_io_threads=64
key_buffer_size=512M
concurrent_insert=2
back_log=512
thread_cache_size=100
thread_stack=192K
interactive_timeout=60
wait_timeout=60
join_buffer_size=4M
read_buffer_size=3M
read_rnd_buffer_size=4M
sort_buffer_size=4M
table_definition_cache=40000
table_open_cache=40000
open_files_limit=60000
max_heap_table_size=128M
tmp_table_size=128M
slow_query_log=0
long_query_time=5
log_queries_not_using_indexes=0

[mysqldump]
quick
max_allowed_packet=1024M

[mysql]
no-auto-rehash

[mysqlhotcopy]
interactive-timeout

[mysqld_safe]
open-files-limit = 8192

[client]
port=3306
plugin-dir=C:/Program Files/MariaDB 10.6/lib/plugin
</code>```

Is there any way to improve the INSERT speed of mariadb ?

答:
in order to compare the same things :
postgresql:

```<code>INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT i,i+1
FROM generate_series(1, 1000000) AS i;
</code>```

mariadb equivalent will be :

```<code>INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT seq,seq+1 FROM seq_1_to_1000000;
</code>```

that would perform better

Body:
I'm comparing MariaDB 10.6 vs PostgreSQL 14 in INSERT operation.
I created a table in both databases, then I tried to insert 1 Million rows in both.
In PostgreSQL, it takes only 2 seconds to INSERT 1 million rows.
But in MariaDB, it takes 9 seconds to INSERT 1 million rows.
But I want to work with MariaDB, so I tried to improve the my.ini but still PostgreSQL is about 2-4 times faster than MariaDB.
This is my table in both databases (no index in both, except the primary key with autoincrement)

CREATE TABLE `project_user` (
    `user_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_username` VARCHAR(16) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_mobile` VARCHAR(16) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_email` VARCHAR(64) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_first_name` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_first_name_en` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_last_name` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_last_name_en` VARCHAR(32) NULL DEFAULT NULL COLLATE 'ascii_general_ci',
    `user_country` TINYINT(3) UNSIGNED NULL DEFAULT NULL,
    `user_gender` BIT(1) NULL DEFAULT NULL,
    `user_registered_ip` INT(10) UNSIGNED NOT NULL,
    `user_registered_at` INT(10) UNSIGNED NOT NULL,
    `user_status` BIT(1) NOT NULL DEFAULT b'1',
    PRIMARY KEY (`user_id`) USING BTREE
)
COLLATE='ascii_general_ci'
ENGINE=InnoDB
;

in PostgreSQL is equal to this table too (except the tinyint which i used bit) ...

In PostgreSQL, I used this operation to insert 1 million rows

INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT i,i+1
FROM generate_series(1, 1000000) AS i;

And in MariaDB I used this function

BEGIN
    FOR i IN 1..1000000
    DO
        INSERT INTO `project_user` (`user_registered_ip`,`user_registered_at`)
        VALUES (i, i+1);
    END FOR;
    RETURN 1;
END

And this is my.ini

[mysqld]
datadir=C:/Program Files/MariaDB 10.6/data
port=3306
max_connections=8192
max_allowed_packet=1G
skip_external_locking
skip_name_resolve
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_buffer_pool_size=24G
innodb_buffer_pool_instances=24
innodb_flush_log_at_trx_commit=0
innodb_flush_method=O_DIRECT
innodb_log_buffer_size=8M
innodb_log_file_size=2G
innodb_sort_buffer_size=16M
innodb_stats_on_metadata=0
innodb_thread_concurrency=6
innodb_read_io_threads=64
innodb_write_io_threads=64
key_buffer_size=512M
concurrent_insert=2
back_log=512
thread_cache_size=100
thread_stack=192K
interactive_timeout=60
wait_timeout=60
join_buffer_size=4M
read_buffer_size=3M
read_rnd_buffer_size=4M
sort_buffer_size=4M
table_definition_cache=40000
table_open_cache=40000
open_files_limit=60000
max_heap_table_size=128M
tmp_table_size=128M
slow_query_log=0
long_query_time=5
log_queries_not_using_indexes=0

[mysqldump]
quick
max_allowed_packet=1024M

[mysql]
no-auto-rehash

[mysqlhotcopy]
interactive-timeout

[mysqld_safe]
open-files-limit = 8192

[client]
port=3306
plugin-dir=C:/Program Files/MariaDB 10.6/lib/plugin

Is there any way to improve the INSERT speed of mariadb ?

Body:
in order to compare the same things :
postgresql:

INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT i,i+1
FROM generate_series(1, 1000000) AS i;

mariadb equivalent will be :

INSERT INTO project_user (user_registered_ip,user_registered_at)
SELECT seq,seq+1 FROM seq_1_to_1000000;

that would perform better


问:
Android Studio Flutter Project Error: Out of Memory
I run any flutter project on Android Studio and it throws an Out Of Memory Error.
The message shown in the console looks something like this:

e:\b\build\slave\windows_engine\build\src\third_party\dart\runtime\vm\scavenger.cc: 411: error: Out of memory.
Dumping native stack trace for thread 2750
  [0x00007ff676324b63] Dart_IsPrecompiledRuntime
  [0x00007ff676324b63] Dart_IsPrecompiledRuntime
-- End of DumpStackTrace
```

答: Just close emulator by task manager. emulator must fully restart</p>


问:
Bevy How to Render Triangle (or Polygon) in 2D
In the bevy examples breakout only uses rectangles, there are examples of loading sprites, there is an example of loading a 3d mesh. In 2d I'd like to draw a triangle (or other polygons), but I haven't been able to figure it out through the docs.</p>

答:
Not sure if that is still relevant, but today I have had the same issue in here is how I have been able to draw simple trianle

```<code>fn create_triangle() -> Mesh {
    let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
    mesh.set_attribute(
        Mesh::ATTRIBUTE_POSITION,
        vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]],
    );
    mesh.set_attribute(Mesh::ATTRIBUTE_COLOR, vec![[0.0, 0.0, 0.0, 1.0]; 3]);
    mesh.set_indices(Some(Indices::U32(vec![0, 1, 2])));
    mesh
}
</code>```

This will create a triangle mesh.
As for me the tricky part was to figure out that by default triangle is drawn transparent and alfa value should be set for the vertexes.
Later you can use this mesh generating function in your system like this:

```<code>fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>
) {
    commands.spawn_bundle(OrthographicCameraBundle::new_2d());
    commands.spawn_bundle(MaterialMesh2dBundle {
    mesh: meshes.add(create_triangle()).into(),
    transform: Transform::default().with_scale(Vec3::splat(128.)),
    material: materials.add(ColorMaterial::from(Color::PURPLE)),
    ..Default::default()
});
</code>```

}

Body:
Not sure if that is still relevant, but today I have had the same issue in here is how I have been able to draw simple trianle

fn create_triangle() -> Mesh {
    let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
    mesh.set_attribute(
        Mesh::ATTRIBUTE_POSITION,
        vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]],
    );
    mesh.set_attribute(Mesh::ATTRIBUTE_COLOR, vec![[0.0, 0.0, 0.0, 1.0]; 3]);
    mesh.set_indices(Some(Indices::U32(vec![0, 1, 2])));
    mesh
}

This will create a triangle mesh.
As for me the tricky part was to figure out that by default triangle is drawn transparent and alfa value should be set for the vertexes.
Later you can use this mesh generating function in your system like this:

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>
) {
    commands.spawn_bundle(OrthographicCameraBundle::new_2d());
    commands.spawn_bundle(MaterialMesh2dBundle {
    mesh: meshes.add(create_triangle()).into(),
    transform: Transform::default().with_scale(Vec3::splat(128.)),
    material: materials.add(ColorMaterial::from(Color::PURPLE)),
    ..Default::default()
});

}


问:
How to improve performance (paralellization or other ideas) calculation of multiple stats of array max, min, mean and std dev?
this is a continuation of this post. I must calculate many times some statistics(Max, mean, min, median and std dev) of arrays and I have a performance issue given the sort of my arrays in the method calcMaxMinMedian.

Given, I could not improve much further the summary statistics of an array performance. I am trying now to understand strategies and work arounds to parallelize my upper calls or any other smart thoughts.

I have seen this doc but I am not familiar
As well as this (post)[https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible/20375622].

I tried using parallel streams, however probably given my SharedResource, the actual performance using the for loop was worse.

```<code>Time (s) functionUsingForLoop173
Time (s) functionUsingParallelStream194
</code>```

Do anyone have an idea of what could I try to parallelize or any other thoughts on how to improve the overrall performance?
Here is what I tried:

```<code>public class MaxMinMedianArrayUtils {
    int[] sharedStaticResource={1,5,5};//Shared resource across

    /**
     * Return an array with summary statistics. Max, mean,std dev,median,min.
     * Throw an IllegalArgumentException if array is empty.
     *
     * @param a array.
     * @return array returning Max(0), mean(1),std dev(2),median(3),min(4) in
     * respective
     * positions.
     */
    public static double[] getSummaryStatistics(double[] a) {
        double[] summary = new double[5];
        if (a.length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (a.length == 1) {
            summary[0] = a[0];
            summary[1] = a[0];
            summary[2] = 0;
            summary[3] = a[0];
            summary[4] = a[0];
        } else {
            double[] meandStd = calcMeanSDSample(a);
            summary[1] = meandStd[0];//Mean
            summary[2] = meandStd[1];//Standard Deviation
            double[] maxMinMedian = calcMaxMinMedian(a);
            summary[0] = maxMinMedian[0];//Max
            summary[4] = maxMinMedian[1];//Min
            summary[3] = maxMinMedian[2];//Median
        }
        return summary;
    }

    public static double[] calcMeanSDSample(double numArray[]) {
        int length = numArray.length;
        double[] meanStd = new double[2];
        if (length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (length == 1) {
            meanStd[0] = numArray[0];
            meanStd[1] = 0.0;
        } else {
            double sum = 0.0, standardDeviation = 0.0;

            for (double num : numArray) {
                sum += num;
            }

            meanStd[0] = sum / length;

            for (double num : numArray) {
                standardDeviation += Math.pow(num - meanStd[0], 2);
            }
            meanStd[1] =
                    Math.sqrt(standardDeviation / ((double) length - 1.0));//-1
            // because it is
            // for sample
        }
        return meanStd;
    }

    public static double[] calcMaxMinMedian(double[] a) {
        double[] maxMinMedian = new double[3];
        if (a.length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (a.length == 1) {
            for (int i = 0; i < 3; i++) {
                maxMinMedian[i] = a[0];
            }
        } else {
            Arrays.sort(a);
            maxMinMedian[0] = a[a.length - 1];
            maxMinMedian[1] = a[0];
            maxMinMedian[2] = (a.length % 2 != 0) ? (double) (a[a.length / 2]) :
                    (double) ((a[(a.length - 1) / 2] + a[a.length / 2]) / 2.0);
        }
        return maxMinMedian;
    }

    public static void main(String[] args) {
        int numVals = 1000;
//        double[] ar = new double[numVals];
        int numCalculations = 2 * 1000 * 1 * 1000;
//        int numCalculations = 2 * 1000;
        MaxMinMedianArrayUtils maxMinMedianArrayUtils=
                new MaxMinMedianArrayUtils();
        Instant start = Instant.now();
        double[][] statsPerCalculation=
                maxMinMedianArrayUtils.functionUsingForLoop(numVals,
                numCalculations);
        Instant end = Instant.now();
        long totalTime = Duration.between(start, end).toSeconds();
        System.out.println("Time (s) functionUsingForLoop" + totalTime);

        Instant start3 = Instant.now();
        double[][] statsPerCalculation3=
                maxMinMedianArrayUtils.functionUsingParallelStream(numVals,
                        numCalculations);
        Instant end3 = Instant.now();
        long totalTime3 = Duration.between(start3, end3).toSeconds();
        System.out.println("Time (s) functionUsingParallelStream" + totalTime3);

    }

    private double[][] functionUsingForLoop(int numVals,
                                  int numCalculations) {
        // calculations that is used to get some values, but is not modified.
        double[][] statsPerCalculation= new double[numCalculations][5];//Each
        // line
        // stores
        // the stats of the array generated in the numCalculations loop
        for (int i = 0; i < numCalculations; i++) {//Complete independent
            // calculations that I want to parallelize
            double[]array=functionSimulateCalculations(numVals);
            double[] stats = getSummaryStatistics(array);
            for(int s = 0; s < stats.length; s++) {//Copy
                statsPerCalculation[i][s] = stats[s];
            }
        }
        return statsPerCalculation;
    }

    private double[][] functionUsingParallelStream(int numVals,
                                           int numCalculations) {
        // calculations that is used to get some values, but is not modified.
        double[][] statsPerCalculation= new double[numCalculations][5];//Each
        // line
        // stores
        // the stats of the array generated in the numCalculations loop
        double[][] finalStatsPerCalculation = statsPerCalculation;
        IntStream.range(0,numCalculations).parallel().forEach((i)->{
                    double[] array=functionSimulateCalculations(numVals);
                    double[] stats = getSummaryStatistics(array);
                    for(int s = 0; s < stats.length; s++) {
                        finalStatsPerCalculation[i][s] = stats[s];
                    }
                }
        );
        return statsPerCalculation;
    }

    private double[] functionSimulateCalculations(int numVals) {
        double[] ar=new double[numVals];
        for (int k = 0; k < numVals; k++) {//To simulate the
            // actual function of my
            // use case
            ar[k] = Math.random()*sharedStaticResource[0];
        }
        return ar;
    }

} // Utility

</code>```

答:
Part of your issue is that you are computing your randomised the data samples inside the tests, but have contention with the singleton random number generation in parallel threads. Also this means that you have no means of validating that the parallel algorithm matches the serial results.

Refactor your tests so that inputs are pre-computed once - you don't care about timing this step:

```<code>private double[][] generateInputData(int numVals, int numCalculations) {
    // calculations that is used to get some values, but is not modified.
    double[][] inputs = new double[numCalculations][];// Each
    for (int i = 0; i < numCalculations; i++) {
        inputs[i] = functionSimulateCalculations(numVals);
    }
    return inputs;
}
</code>```

Then you can run both tests on same inputs:

```<code>private double[][] functionUsingForLoop(double[][]arrays) {
    // calculations that is used to get some values, but is not modified.
    int numCalculations = arrays.length;
    double[][] statsPerCalculation = new double[numCalculations][5];// Each
    for (int i = 0; i < numCalculations; i++) {
        double[] stats = getSummaryStatistics(arrays[i]);
        for (int s = 0; s < stats.length; s++) {
            statsPerCalculation[i][s] = stats[s];
        }
    }
    return statsPerCalculation;
}
private double[][] functionUsingParallelStream(double[][]arrays) {
    int numCalculations = arrays.length;
    double[][] statsPerCalculation = new double[numCalculations][5];// Each
    double[][] finalStatsPerCalculation = statsPerCalculation;
    IntStream.range(0, numCalculations).parallel().forEach((i) -> {
        double[] stats = getSummaryStatistics(arrays[i]);
        for (int s = 0; s < stats.length; s++) {
            finalStatsPerCalculation[i][s] = stats[s];
        }
    });
    return statsPerCalculation;
}
</code>```

Finally make your main() do some warmups, initialise the arrays, time each section and compare the results:

```<code>for (int numCalculations : new int[] { 1, 2, 8, 8, 2 * 1000, 2* 10000, 2*1000*1*1000 } ) {
    double[][] arrays = maxMinMedianArrayUtils.generateInputData(numVals, numCalculations);
    // ...
    double[][] statsPerCalculation= maxMinMedianArrayUtils.functionUsingForLoop(arrays);
    // ...
    double[][] statsPerCalculation3= maxMinMedianArrayUtils.functionUsingParallelStream(arrays);
    // ...
    // COMPARE the results
    if (statsPerCalculation3.length != statsPerCalculation.length)
        throw new RuntimeException("Results not same!");
    for (int i = statsPerCalculation3.length - 1; i >= 0; i--) {
       // System.out.println("statsPerCalculation ["+i+"]="+Arrays.toString(statsPerCalculation[i]));
       // System.out.println("statsPerCalculation3["+i+"]="+Arrays.toString(statsPerCalculation3[i]));
        for (int v = statsPerCalculation3[i].length - 1; v >= 0; v--) {
            if (Math.abs(statsPerCalculation3[i][v]-statsPerCalculation[i][v]) > 0.0000000000001)
                throw new RuntimeException("Results not same at ["+i+"]["+v+"]");
        }
    }
}
</code>```

At this point, you'll see quite different trend in the results, parallel stream version a lot quicker than non-parallel.

Body:
this is a continuation of this post. I must calculate many times some statistics(Max, mean, min, median and std dev) of arrays and I have a performance issue given the sort of my arrays in the method calcMaxMinMedian.

Given, I could not improve much further the summary statistics of an array performance. I am trying now to understand strategies and work arounds to parallelize my upper calls or any other smart thoughts.

I have seen this doc but I am not familiar
As well as this (post)[https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible/20375622].

I tried using parallel streams, however probably given my SharedResource, the actual performance using the for loop was worse.

Time (s) functionUsingForLoop173
Time (s) functionUsingParallelStream194

Do anyone have an idea of what could I try to parallelize or any other thoughts on how to improve the overrall performance?
Here is what I tried:

public class MaxMinMedianArrayUtils {
    int[] sharedStaticResource={1,5,5};//Shared resource across

    /**
     * Return an array with summary statistics. Max, mean,std dev,median,min.
     * Throw an IllegalArgumentException if array is empty.
     *
     * @param a array.
     * @return array returning Max(0), mean(1),std dev(2),median(3),min(4) in
     * respective
     * positions.
     */
    public static double[] getSummaryStatistics(double[] a) {
        double[] summary = new double[5];
        if (a.length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (a.length == 1) {
            summary[0] = a[0];
            summary[1] = a[0];
            summary[2] = 0;
            summary[3] = a[0];
            summary[4] = a[0];
        } else {
            double[] meandStd = calcMeanSDSample(a);
            summary[1] = meandStd[0];//Mean
            summary[2] = meandStd[1];//Standard Deviation
            double[] maxMinMedian = calcMaxMinMedian(a);
            summary[0] = maxMinMedian[0];//Max
            summary[4] = maxMinMedian[1];//Min
            summary[3] = maxMinMedian[2];//Median
        }
        return summary;
    }

    public static double[] calcMeanSDSample(double numArray[]) {
        int length = numArray.length;
        double[] meanStd = new double[2];
        if (length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (length == 1) {
            meanStd[0] = numArray[0];
            meanStd[1] = 0.0;
        } else {
            double sum = 0.0, standardDeviation = 0.0;

            for (double num : numArray) {
                sum += num;
            }

            meanStd[0] = sum / length;

            for (double num : numArray) {
                standardDeviation += Math.pow(num - meanStd[0], 2);
            }
            meanStd[1] =
                    Math.sqrt(standardDeviation / ((double) length - 1.0));//-1
            // because it is
            // for sample
        }
        return meanStd;
    }

    public static double[] calcMaxMinMedian(double[] a) {
        double[] maxMinMedian = new double[3];
        if (a.length == 0) {
            throw new IllegalArgumentException(
                    "Array is empty, please " + "verify" + " the values.");
        } else if (a.length == 1) {
            for (int i = 0; i < 3; i++) {
                maxMinMedian[i] = a[0];
            }
        } else {
            Arrays.sort(a);
            maxMinMedian[0] = a[a.length - 1];
            maxMinMedian[1] = a[0];
            maxMinMedian[2] = (a.length % 2 != 0) ? (double) (a[a.length / 2]) :
                    (double) ((a[(a.length - 1) / 2] + a[a.length / 2]) / 2.0);
        }
        return maxMinMedian;
    }

    public static void main(String[] args) {
        int numVals = 1000;
//        double[] ar = new double[numVals];
        int numCalculations = 2 * 1000 * 1 * 1000;
//        int numCalculations = 2 * 1000;
        MaxMinMedianArrayUtils maxMinMedianArrayUtils=
                new MaxMinMedianArrayUtils();
        Instant start = Instant.now();
        double[][] statsPerCalculation=
                maxMinMedianArrayUtils.functionUsingForLoop(numVals,
                numCalculations);
        Instant end = Instant.now();
        long totalTime = Duration.between(start, end).toSeconds();
        System.out.println("Time (s) functionUsingForLoop" + totalTime);

        Instant start3 = Instant.now();
        double[][] statsPerCalculation3=
                maxMinMedianArrayUtils.functionUsingParallelStream(numVals,
                        numCalculations);
        Instant end3 = Instant.now();
        long totalTime3 = Duration.between(start3, end3).toSeconds();
        System.out.println("Time (s) functionUsingParallelStream" + totalTime3);

    }

    private double[][] functionUsingForLoop(int numVals,
                                  int numCalculations) {
        // calculations that is used to get some values, but is not modified.
        double[][] statsPerCalculation= new double[numCalculations][5];//Each
        // line
        // stores
        // the stats of the array generated in the numCalculations loop
        for (int i = 0; i < numCalculations; i++) {//Complete independent
            // calculations that I want to parallelize
            double[]array=functionSimulateCalculations(numVals);
            double[] stats = getSummaryStatistics(array);
            for(int s = 0; s < stats.length; s++) {//Copy
                statsPerCalculation[i][s] = stats[s];
            }
        }
        return statsPerCalculation;
    }

    private double[][] functionUsingParallelStream(int numVals,
                                           int numCalculations) {
        // calculations that is used to get some values, but is not modified.
        double[][] statsPerCalculation= new double[numCalculations][5];//Each
        // line
        // stores
        // the stats of the array generated in the numCalculations loop
        double[][] finalStatsPerCalculation = statsPerCalculation;
        IntStream.range(0,numCalculations).parallel().forEach((i)->{
                    double[] array=functionSimulateCalculations(numVals);
                    double[] stats = getSummaryStatistics(array);
                    for(int s = 0; s < stats.length; s++) {
                        finalStatsPerCalculation[i][s] = stats[s];
                    }
                }
        );
        return statsPerCalculation;
    }

    private double[] functionSimulateCalculations(int numVals) {
        double[] ar=new double[numVals];
        for (int k = 0; k < numVals; k++) {//To simulate the
            // actual function of my
            // use case
            ar[k] = Math.random()*sharedStaticResource[0];
        }
        return ar;
    }

} // Utility

Body:
Part of your issue is that you are computing your randomised the data samples inside the tests, but have contention with the singleton random number generation in parallel threads. Also this means that you have no means of validating that the parallel algorithm matches the serial results.

Refactor your tests so that inputs are pre-computed once - you don't care about timing this step:

private double[][] generateInputData(int numVals, int numCalculations) {
    // calculations that is used to get some values, but is not modified.
    double[][] inputs = new double[numCalculations][];// Each
    for (int i = 0; i < numCalculations; i++) {
        inputs[i] = functionSimulateCalculations(numVals);
    }
    return inputs;
}

Then you can run both tests on same inputs:

private double[][] functionUsingForLoop(double[][]arrays) {
    // calculations that is used to get some values, but is not modified.
    int numCalculations = arrays.length;
    double[][] statsPerCalculation = new double[numCalculations][5];// Each
    for (int i = 0; i < numCalculations; i++) {
        double[] stats = getSummaryStatistics(arrays[i]);
        for (int s = 0; s < stats.length; s++) {
            statsPerCalculation[i][s] = stats[s];
        }
    }
    return statsPerCalculation;
}
private double[][] functionUsingParallelStream(double[][]arrays) {
    int numCalculations = arrays.length;
    double[][] statsPerCalculation = new double[numCalculations][5];// Each
    double[][] finalStatsPerCalculation = statsPerCalculation;
    IntStream.range(0, numCalculations).parallel().forEach((i) -> {
        double[] stats = getSummaryStatistics(arrays[i]);
        for (int s = 0; s < stats.length; s++) {
            finalStatsPerCalculation[i][s] = stats[s];
        }
    });
    return statsPerCalculation;
}

Finally make your main() do some warmups, initialise the arrays, time each section and compare the results:

for (int numCalculations : new int[] { 1, 2, 8, 8, 2 * 1000, 2* 10000, 2*1000*1*1000 } ) {
    double[][] arrays = maxMinMedianArrayUtils.generateInputData(numVals, numCalculations);
    // ...
    double[][] statsPerCalculation= maxMinMedianArrayUtils.functionUsingForLoop(arrays);
    // ...
    double[][] statsPerCalculation3= maxMinMedianArrayUtils.functionUsingParallelStream(arrays);
    // ...
    // COMPARE the results
    if (statsPerCalculation3.length != statsPerCalculation.length)
        throw new RuntimeException("Results not same!");
    for (int i = statsPerCalculation3.length - 1; i >= 0; i--) {
       // System.out.println("statsPerCalculation ["+i+"]="+Arrays.toString(statsPerCalculation[i]));
       // System.out.println("statsPerCalculation3["+i+"]="+Arrays.toString(statsPerCalculation3[i]));
        for (int v = statsPerCalculation3[i].length - 1; v >= 0; v--) {
            if (Math.abs(statsPerCalculation3[i][v]-statsPerCalculation[i][v]) > 0.0000000000001)
                throw new RuntimeException("Results not same at ["+i+"]["+v+"]");
        }
    }
}

At this point, you'll see quite different trend in the results, parallel stream version a lot quicker than non-parallel.


问:
React Native error redirecting to Homepage after user login
I am writing an application with react native. When the user opens the application, if there is no session token, the Welcome.js screen opens first. Then he clicks on the Login.js screen to log in. If the login is successful, I am trying to redirect to the Homepage. But I just couldn't. It gives an error. The error I get is this:

[

The action 'NAVIGATE' with payload {"name":"Home"} was not handled by any navigator.
Do you have a screen named 'Home'?

]

**App.js Code**

import React, {useState,useEffect} from 'react';
import { LogBox,Linking } from 'react-native';
import { createDrawerNavigator,DrawerContentScrollView,DrawerItemList,DrawerItem } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AsyncStorage from '@react-native-async-storage/async-storage';
import FirstPages from './src/screens/FirstPages';
import Home from './src/screens/Home';
import Notification from './src/screens/Notification';
import Message from './src/screens/Message';
import MessageDetail from './src/screens/MessageDetail';
import Profile from './src/screens/Profile';

LogBox.ignoreLogs(['NativeBase:']);

function App() {

  const [user,setUser] = useState(false);

    //AsyncStorage.removeItem("user");
    useEffect(()=>{
      AsyncStorage.getItem('user').then((value)=>(
        setUser(value != null && JSON.parse(value).id ? value : false )
      ));
    });

  const Tab = createBottomTabNavigator();
  const Drawer = createDrawerNavigator();
  const MessageStack = createNativeStackNavigator();

function MessageMain (){
  return(
      <MessageStack.Navigator screenOptions={{headerShown: false}}>
        <MessageStack.Screen name="Message" component={Message} />
        <MessageStack.Screen name="MessageDetail" component={MessageDetail} />
      </MessageStack.Navigator>
    )
};

  function BottomTab(){
    return (
      <Tab.Navigator screenOptions={{headerShown:false}}>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Notification" component={Notification} />
        <Tab.Screen name="Message" component={MessageMain} />
        <Tab.Screen name="Profile" component={Profile} />
      </Tab.Navigator>
    )
  }

  return (
      <NavigationContainer>
        {
          user ?
            <Drawer.Navigator initialRouteName="Home3" screenOptions={{headerShown: false}} >
              <Drawer.Screen name="Home3" component={BottomTab} />
            </Drawer.Navigator>
          :
            <FirstPages />
        }
      </NavigationContainer>
  );
}

export default App;

**Login.js**

import React, {useState,useEffect} from 'react';
import { LogBox,KeyboardAvoidingView  } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { FontAwesome } from '@expo/vector-icons';
import { Input,Image,View,Text,NativeBaseProvider,Button,ScrollView,Icon,Modal,FormControl } from 'native-base';
import AsyncStorage from '@react-native-async-storage/async-storage';
import colors from "../config/colors";

LogBox.ignoreLogs(['NativeBase:']);

function Login( {navigation} ) {

  const storeSetData = async (value) => {
    try {
      await AsyncStorage.setItem('user', value)
    } catch (e) {
      alert("Hata oluştu!");
      return false;
    }
  }

//Login Post İşlemi
const LoginPost = (  )=>{

  setRequestPost(true);

  setButtonPost("İşleniyor...");

  const formData = new FormData();

  formData.append("user_login",1);
  formData.append("u_name",userName);
  formData.append("u_pass",userPass);

  fetch(API_URL, {
      method: 'post',
      body: formData,
    })
      .then((response) => response.json())
      .then((responseData) => {

        if(responseData.success){

          const dataStringify = JSON.stringify({
            id:responseData.user.u_id,
            full_name:responseData.user.u_full_name,
            name:responseData.user.u_name,
            image:responseData.user.u_image
          });

          storeSetData(dataStringify);

            //storage kayıt işleminde hata varsa uyar
            if(!storeSetData){
              setAlertModal( { message:"Hata oluştu!",type:"error" });
              setShowModal(true);
              return false;
            }

            setAlertModal( { message:responseData.success,type:"success" });

            //redirect
            navigation.navigate("Home");

        }else{
          setAlertModal( { message:responseData.error,type:"error" });
        }

        setShowModal(true);
        setButtonPost("Giriş Yap");
      })
      .catch((error) => {
        setAlertModal( { message:"Bir hata oluştu!",type:"error" } );
        setButtonPost("Giriş Yap");
      })
      .finally(()=>{
        setButtonPost("Giriş Yap");
        setRequestPost(false);
      });

}

  return (
    <NativeBaseProvider>
        <LinearGradient
            colors={['rgba(255, 221, 214, .95)', 'rgba(249, 241, 214, .9)']}
            start={{ x: 0.65, y: 0.33 }}
            end={{ x: 0.35, y: 0.33 }}
            flex={1}
          >
            <KeyboardAvoidingView
              behavior={Platform.OS == "ios" ? "padding" : "height"}
            >

            <ScrollView>

              <View flex="1" pt="5" pb="0" px={5}>

                  <Image
                    source={require("../img/login.png")}
                    alt="Alternate Text"
                    flex="1"
                  />

                </View>

            </ScrollView>

            </KeyboardAvoidingView>
          </LinearGradient>
    </NativeBaseProvider>
  );
}

export default Login;

**FirstPages.js**

import React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Welcome from './Welcome';
import Register from './Register';
import Login from './Login';

const Stack = createNativeStackNavigator();

const FirstPages = () => {

    return(
        <Stack.Navigator screenOptions={{headerShown: false}}>
          <Stack.Screen name="Welcome" component={Welcome} />
          <Stack.Screen name="Register" component={Register} />
          <Stack.Screen name="Login" component={Login} />
        </Stack.Navigator>
      )

};

export default FirstPages;```

答:
You cannot navigate to a screen outside the current navigator like that.

It is recommended that you use the authentication flow in the react navigation docs here: https://reactnavigation.org/docs/auth-flow

It uses conditional operations to change the navigator, instead of directly navigating to a screen.

For Example:

```<code>isSignedIn ? (
  <>
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Profile" component={ProfileScreen} />
    <Stack.Screen name="Settings" component={SettingsScreen} />
  </>
) : (
  <>
    <Stack.Screen name="SignIn" component={SignInScreen} />
    <Stack.Screen name="SignUp" component={SignUpScreen} />
  </>
)
</code>```

Source: https://reactnavigation.org/docs/auth-flow#how-it-will-work

Body:
You cannot navigate to a screen outside the current navigator like that.

It is recommended that you use the authentication flow in the react navigation docs here: https://reactnavigation.org/docs/auth-flow

It uses conditional operations to change the navigator, instead of directly navigating to a screen.

For Example:

isSignedIn ? (
  <>
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Profile" component={ProfileScreen} />
    <Stack.Screen name="Settings" component={SettingsScreen} />
  </>
) : (
  <>
    <Stack.Screen name="SignIn" component={SignInScreen} />
    <Stack.Screen name="SignUp" component={SignUpScreen} />
  </>
)

Source: https://reactnavigation.org/docs/auth-flow#how-it-will-work


问:
Can I change the access modifier of generated safe nav args?
I am using safe nav args in my application. The point is that I have an internal class that should be passed from fragment A to fragment B. Both fragments are internal as well. The generated safe args class is public so I get that error.

```<code>'public' function exposes its 'internal' parameter
</code>```

which makes sense.

My question is can I change the access modifier of the generated nav args class?

答:
The problem got resolved in version

```<code>classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0"
</code>```

and by applying the plugin

```<code>apply plugin: "androidx.navigation.safeargs"
</code>```

instead of

```<code>apply plugin: "androidx.navigation.safeargs.kotlin"
</code>```

Body:
I am using safe nav args in my application. The point is that I have an internal class that should be passed from fragment A to fragment B. Both fragments are internal as well. The generated safe args class is public so I get that error.

'public' function exposes its 'internal' parameter

which makes sense.

My question is can I change the access modifier of the generated nav args class?

Body:
The problem got resolved in version

classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0"

and by applying the plugin

apply plugin: "androidx.navigation.safeargs"

instead of

apply plugin: "androidx.navigation.safeargs.kotlin"