จะเข้าร่วม int [] กับสตริงที่คั่นด้วยอักขระใน. NET ได้อย่างไร


101

ฉันมีอาร์เรย์ของจำนวนเต็ม:

int[] number = new int[] { 2,3,6,7 };

วิธีที่ง่ายที่สุดในการแปลงสิ่งเหล่านี้เป็นสตริงเดียวโดยที่ตัวเลขถูกคั่นด้วยอักขระ (เช่น:) "2,3,6,7"คืออะไร?

ฉันอยู่ใน C # และ. NET 3.5


3
หินมาก! ฉันได้รับคำตอบที่ยอดเยี่ยม 3 ข้อนี้ภายใน 10 นาทีในวันอาทิตย์!
Riri

4
ขณะที่.NET 4.0มีวิธีการที่ใช้อาร์เรย์ของวัตถุและ IEnumerable string.join(",", number)เพื่อให้คุณก็สามารถทำ ฉันรู้ว่าคำถามระบุ. NET 3.5 ดังนั้นฉันจึงไม่ได้ให้คำตอบนี้ แต่เกิดขึ้นในการค้นหาที่ไม่ระบุเวอร์ชันและรู้ว่าเป็นไปได้ใน 4.0 สามารถช่วยใครบางคนได้
Jason Goemaat

คำตอบ:


162
var ints = new int[] {1, 2, 3, 4, 5};
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());
Console.WriteLine(result); // prints "1,2,3,4,5"

แก้ไข : ณ วันที่ (อย่างน้อย) .NET 4.5,

var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());

เทียบเท่ากับ:

var result = string.Join(",", ints);

แก้ไข :

ฉันเห็นโซลูชันหลายรายการโฆษณาการใช้งาน StringBuilder มีคนร้องเรียนว่าวิธีเข้าร่วมควรใช้อาร์กิวเมนต์ที่สามารถคำนวณได้ของ IE

ฉันจะทำให้คุณผิดหวัง :) String.Join ต้องการอาร์เรย์ด้วยเหตุผลเดียวนั่นคือประสิทธิภาพ วิธีการเข้าร่วมจำเป็นต้องทราบขนาดของข้อมูลเพื่อจัดสรรหน่วยความจำที่จำเป็นล่วงหน้าอย่างมีประสิทธิภาพ

นี่คือส่วนหนึ่งของการใช้งานวิธีการ String.Join ภายใน:

// length computed from length of items in input array and length of separator
string str = FastAllocateString(length);
fixed (char* chRef = &str.m_firstChar) // note than we use direct memory access here
{
    UnSafeCharBuffer buffer = new UnSafeCharBuffer(chRef, length);
    buffer.AppendString(value[startIndex]);
    for (int j = startIndex + 1; j <= num2; j++)
    {
        buffer.AppendString(separator);
        buffer.AppendString(value[j]);
    }
}

ฉันขี้เกียจเกินไปที่จะเปรียบเทียบประสิทธิภาพของวิธีการที่แนะนำ แต่มีบางอย่างบอกฉันว่าเข้าร่วมจะชนะ :)


นี่อาจเป็นทางออกที่ดีที่สุดโดยใช้วิธีการขยาย. NET หลัก แต่ฉันต้องการสตริงเข้าร่วม () จะยอมรับ <string> ของ IEnumerable เพื่อหลีกเลี่ยงการแปลง ToArray ()
spoulson

ไม่มีอะไรป้องกันไม่ให้ใครบางคนใช้สายอักขระมากเกินไปเข้าร่วมเพื่อใช้ IEnumerable ด้วย ;)
Robert P

1
นี่อาจเป็นวิธีแก้ปัญหาที่ง่ายที่สุดและไม่ใช่แค่เร็วที่สุด
Dave Van den Eynde

9
.NET 4 จัดเตรียม String เข้าร่วมโอเวอร์โหลดที่ยอมรับ IEnumerable เป็นพารามิเตอร์ msdn.microsoft.com/en-us/library/dd783876.aspx
Ryan Kohn

using System.Linq;ต้องระบุ.
Gayan Weerakutti

32

แม้ว่า OP จะระบุ. NET 3.5 แต่ผู้ที่ต้องการทำสิ่งนี้ใน. NET 2.0 ด้วย C # 2 สามารถทำได้:

string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));

ฉันพบว่ามีอีกหลายกรณีที่การใช้ฟังก์ชัน Convert.xxx เป็นทางเลือกที่ดีกว่าแลมด้าแม้ว่าใน C # 3 แลมบ์ดาอาจช่วยในการอนุมานประเภทได้

รุ่น C # 3 ที่ค่อนข้างกะทัดรัดซึ่งใช้งานได้กับ. NET 2.0 คือ:

string.Join(",", Array.ConvertAll(ints, item => item.ToString()))

11

ส่วนผสมหนึ่งของสองวิธีคือการเขียนวิธีการขยายบน IEnumerable <T> ซึ่งใช้ StringBuilder นี่คือตัวอย่างที่มีโอเวอร์โหลดที่แตกต่างกันขึ้นอยู่กับว่าคุณต้องการระบุการแปลงหรือเพียงแค่พึ่งพา ToString ธรรมดา ฉันตั้งชื่อเมธอดว่า "JoinStrings" แทน "Join" เพื่อหลีกเลี่ยงความสับสนกับการเข้าร่วมประเภทอื่น บางทีอาจมีคนคิดชื่อที่ดีกว่านี้ก็ได้ :)

using System;
using System.Collections.Generic;
using System.Text;

public static class Extensions
{
    public static string JoinStrings<T>(this IEnumerable<T> source, 
                                        Func<T, string> projection, string separator)
    {
        StringBuilder builder = new StringBuilder();
        bool first = true;
        foreach (T element in source)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                builder.Append(separator);
            }
            builder.Append(projection(element));
        }
        return builder.ToString();
    }

    public static string JoinStrings<T>(this IEnumerable<T> source, string separator)
    {
        return JoinStrings(source, t => t.ToString(), separator);
    }
}

class Test
{

    public static void Main()
    {
        int[] x = {1, 2, 3, 4, 5, 10, 11};

        Console.WriteLine(x.JoinStrings(";"));
        Console.WriteLine(x.JoinStrings(i => i.ToString("X"), ","));
    }
}

ทางออกที่ดี! คุณไม่ต้องการพารามิเตอร์การฉาย แต่คุณสามารถเขียน x เลือก (i => i ToString ("X")) JoinStrings (";") ซึ่งเป็นสำนวนมากกว่า
JacquesB

ใช่ฉันคิดเกี่ยวกับเรื่องนั้นในภายหลัง ในบางครั้งมันก็เป็นเรื่องดีที่สามารถระบุได้ทั้งหมดในครั้งเดียว แต่การแยกการดำเนินการจะดีกว่าอย่างแน่นอน :)
Jon Skeet

8
String.Join(";", number.Select(item => item.ToString()).ToArray());

เราต้องแปลงแต่ละรายการเป็น a Stringก่อนจึงจะเข้าร่วมได้ดังนั้นจึงเหมาะสมที่จะใช้Selectและนิพจน์แลมบ์ดา ซึ่งเทียบเท่ากับmapในภาษาอื่น ๆ จากนั้นเราต้องแปลงคอลเลคชันสตริงที่เป็นผลลัพธ์กลับไปเป็นอาร์เรย์เนื่องจากString.Joinยอมรับเฉพาะสตริงอาร์เรย์เท่านั้น

ToArray()น่าเกลียดเล็กน้อยผมคิดว่า String.JoinควรยอมรับจริงๆIEnumerable<String>ไม่มีเหตุผลที่จะ จำกัด เฉพาะอาร์เรย์เท่านั้น นี่อาจเป็นเพียงเพราะJoinมาก่อนชื่อสามัญเมื่ออาร์เรย์เป็นคอลเลกชันชนิดเดียวที่มีอยู่


5

หากอาร์เรย์จำนวนเต็มของคุณมีขนาดใหญ่คุณจะได้รับประสิทธิภาพที่ดีขึ้นโดยใช้ StringBuilder เช่น:

StringBuilder builder = new StringBuilder();
char separator = ',';
foreach(int value in integerArray)
{
    if (builder.Length > 0) builder.Append(separator);
    builder.Append(value);
}
string result = builder.ToString();

แก้ไข: เมื่อฉันโพสต์สิ่งนี้ฉันอยู่ภายใต้การแสดงผลที่ผิดพลาดว่า "StringBuilder.Append (ค่า int)" ถูกจัดการภายในเพื่อผนวกการแสดงสตริงของค่าจำนวนเต็มโดยไม่ต้องสร้างวัตถุสตริง สิ่งนี้ผิด: การตรวจสอบเมธอดด้วยตัวสะท้อนแสงแสดงให้เห็นว่ามันเพิ่มค่าเท่านั้น ToString ()

ดังนั้นความแตกต่างของประสิทธิภาพที่เป็นไปได้เพียงอย่างเดียวคือเทคนิคนี้จะหลีกเลี่ยงการสร้างอาร์เรย์เดียวและทำให้สตริงสำหรับการรวบรวมขยะเร็วขึ้นเล็กน้อย ในทางปฏิบัติสิ่งนี้จะไม่สร้างความแตกต่างที่วัดได้ดังนั้นฉันจึงยกระดับวิธีแก้ปัญหาที่ดีกว่านี้


คุณวัดได้เร็วขึ้นหรือไม่? String.Join ใช้ StringBuilder ด้วย
JacquesB

ใช่ แต่ก่อนอื่นคุณต้องแปลงสิ่งทั้งหมดเป็นอาร์เรย์ซึ่งอยู่ไกลจากอุดมคติ โดยเฉพาะอย่างยิ่งหมายความว่าคุณต้องมีสตริงที่แปลงแล้วทั้งหมดในหน่วยความจำในเวลาเดียวกันก่อนที่คุณจะเริ่มสร้างสตริงผลลัพธ์
Jon Skeet

OTOH String เข้าร่วมคำนวณขนาดของบัฟเฟอร์ StringBuilder ล่วงหน้าเพื่อหลีกเลี่ยงการปรับขนาด ดังนั้นจึงอาจเร็วขึ้นแม้ว่าจะต้องใช้หน่วยความจำมากขึ้นก็ตาม
JacquesB

5

คำถามนี้มีไว้สำหรับ "วิธีที่ง่ายที่สุดในการแปลงสิ่งเหล่านี้เป็นสตริงเดี่ยวโดยที่ตัวเลขจะถูกคั่นด้วยอักขระ"

วิธีที่ง่ายที่สุดคือ:

int[] numbers = new int[] { 2,3,6,7 };
string number_string = string.Join(",", numbers);
// do whatever you want with your exciting new number string

แก้ไข: ใช้งานได้เฉพาะใน. NET 4.0+ ฉันพลาดข้อกำหนด. NET 3.5 ในครั้งแรกที่อ่านคำถาม


ไม่ถูกต้องเป็นสตริงวิธีการเข้าร่วมใช้อาร์เรย์ของสตริงเท่านั้น ลองดูที่นี่ msdn.microsoft.com/en-us/library/tk0xe5h0.aspx
ppolyzos

1
เป็นวิธีที่โอเวอร์โหลด: msdn.microsoft.com/en-us/library/dd988350ฉันเพิ่งคัดลอกรหัสที่ฉันเขียนลงในแอปคอนโซลใหม่เพิ่ม Console.WriteLine และนี่คือผลลัพธ์: 2,3,6,7
WebMasterP

1
ฉันคิดว่าสิ่งนี้มีให้ใน. net 4 เท่านั้น
Govind Malviya

ต้องใช้อาร์เรย์อ็อบเจ็กต์ (หรือสตริงอาร์เรย์) ไม่ใช่อาร์เรย์ int จะให้ข้อผิดพลาด "การโทรไม่ชัดเจน"
LarryBud

2

ฉันเห็นด้วยกับนิพจน์แลมบ์ดาสำหรับความสามารถในการอ่านและการบำรุงรักษา แต่มันจะไม่ใช่ตัวเลือกที่ดีที่สุดเสมอไป ข้อเสียของการใช้ทั้งวิธี IEnumerable / ToArray และ StringBuilder คือพวกเขาต้องขยายรายการแบบไดนามิกไม่ว่าจะเป็นรายการหรืออักขระใด ๆ เนื่องจากพวกเขาไม่ทราบว่าจะต้องใช้พื้นที่เท่าใดสำหรับสตริงสุดท้าย

หากเกิดขึ้นได้ยากที่ความเร็วมีความสำคัญมากกว่าความรัดกุมสิ่งต่อไปนี้จะมีประสิทธิภาพมากกว่า

int[] number = new int[] { 1, 2, 3, 4, 5 };
string[] strings = new string[number.Length];
for (int i = 0; i < number.Length; i++)
  strings[i] = number[i].ToString();
string result = string.Join(",", strings);

2
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);

ฉันยังคิดว่ามีวิธีที่ง่ายกว่านี้ ไม่รู้เกี่ยวกับประสิทธิภาพใครมีความคิด (เชิงทฤษฎี) บ้างไหม?


โซลูชันนี้จะให้ ", 1,2,3,4,5"
สาริน

ขอบคุณฉันได้เพิ่มSubstring(1)เพื่อแก้ไขแล้ว (มาจากหน่วยความจำ)
เป็นโมฆะ

2

ใน. NET 4.0 การรวมสตริงมีโอเวอร์โหลดparams object[]ดังนั้นจึงทำได้ง่ายเพียงแค่:

int[] ids = new int[] { 1, 2, 3 };
string.Join(",", ids);

ตัวอย่าง

int[] ids = new int[] { 1, 2, 3 };
System.Data.Common.DbCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM some_table WHERE id_column IN (@bla)");
cmd.CommandText = cmd.CommandText.Replace("@bla",  string.Join(",", ids));

ใน. NET 2.0 นั้นยากกว่าเล็กน้อยเนื่องจากไม่มีการโอเวอร์โหลด ดังนั้นคุณต้องมีวิธีการทั่วไปของคุณเอง:

public static string JoinArray<T>(string separator, T[] inputTypeArray)
{
    string strRetValue = null;
    System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

    for (int i = 0; i < inputTypeArray.Length; ++i)
    {
        string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture);

        if (!string.IsNullOrEmpty(str))
        { 
            // SQL-Escape
            // if (typeof(T) == typeof(string))
            //    str = str.Replace("'", "''");

            ls.Add(str);
        } // End if (!string.IsNullOrEmpty(str))

    } // Next i 

    strRetValue= string.Join(separator, ls.ToArray());
    ls.Clear();
    ls = null;

    return strRetValue;
}

ใน. NET 3.5 คุณสามารถใช้วิธีการขยาย:

public static class ArrayEx
{

    public static string JoinArray<T>(this T[] inputTypeArray, string separator)
    {
        string strRetValue = null;
        System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();

        for (int i = 0; i < inputTypeArray.Length; ++i)
        {
            string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture);

            if (!string.IsNullOrEmpty(str))
            { 
                // SQL-Escape
                // if (typeof(T) == typeof(string))
                //    str = str.Replace("'", "''");

                ls.Add(str);
            } // End if (!string.IsNullOrEmpty(str))

        } // Next i 

        strRetValue= string.Join(separator, ls.ToArray());
        ls.Clear();
        ls = null;

        return strRetValue;
    }

}

ดังนั้นคุณสามารถใช้วิธีการขยาย JoinArray

int[] ids = new int[] { 1, 2, 3 };
string strIdList = ids.JoinArray(",");

คุณยังสามารถใช้วิธีการขยายนั้นใน. NET 2.0 ได้หากคุณเพิ่ม ExtensionAttribute ลงในโค้ดของคุณ:

// you need this once (only), and it must be in this namespace
namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class ExtensionAttribute : Attribute {}
}

1

8
ต้องใช้วิธีการขยายที่กำหนดไว้ในหน้าที่เชื่อมโยงซึ่งอาจชัดเจนกว่า
StocksR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.