2

これが私の問題です

私は次の配列を持っています(例えば)

string[] arr = new[] { "s_0001", "s_0002", "s_0003", "sa_0004", "sa_0005", "sab_0006", "sab_0007" };

次のような出力をしたい

s_0001
sa_0004
sab_0006

私はすべてを試しましたが、運がありません!これは長いプロジェクトの最初のステップであり、どんな助けでも大歓迎です。

[編集]文字がいつ変わるかはわかりませんが、文字と数字を区切るためのアンダースコアが常に存在することは知っています。どういうわけかこれらの文字を抽出してから、重複する文字を取り除く必要があります

[編集]より具体的には、アンダースコアの前に各文字列の一意のエントリを設定したいのですが、数字は気にしません

[編集]OKみんな!あなたは本当にアクティブです私はあなたにそれを与えます。こんなに早く答えられるとは思っていませんでした。しかし、どうやら(私は過去8時間これに取り組んできたので)、私は間違った質問をしました

これが私のコードです

//Loop through the XML files in the Directory and get
//the objectName and GUID of each file
string[] arr_xmlFiles = Directory.GetFiles(Dir, "*.xml");   //Array with all XML Files in the Directory

foreach (string xmlFile in arr_xmlFiles)
{
    try
    {
        //Get the XMLs Name
        XDocument xmlF = XDocument.Load(xmlFile);
        string objectName = xmlF.Root.Name.ToString();

        //Get the XMLs GUID
        XElement oDcElement = xmlF.Root.FirstNode as XElement;
        Guid oGuid = new Guid(oDcElement.Attribute("DataclassId").Value);

        //Prints out the results 
        Console.WriteLine(" " + objectName + "    " + oGuid);
    }
    catch (XmlException) { }
}

私が基本的に行っているのは、ディレクトリ内のすべてのXMLファイルを取得することです(それらには、GUIDを含むObjectNameが含まれています)

すなわち

CM_Commands [0ee2ab91-4971-4fd3-9752-cf47c8ba4a01].xml    
CM_Commands [1f627f72-ca7b-4b07-8f93-c5750612c209].xml

申し訳ありませんが、区切り記号は「[」ではなく「_」でしたが、問題ではありません。

次に、これらすべてのXMLを配列に保存し、これらのXMLからそれぞれのObjectNameとGUIDを抽出します。

その後、同じobjectNameを保持する各XMLの1つだけにいくつかの変更を加えたいと思います。

それで全部です

4

7 に答える 7

3

編集#3:以下のスニペットに追加された詳細なコメント(編集2の下の更新されたコードを参照)。また、これらをメソッドから返したい場合は、次のようなこれらのプロパティを使用して新しいクラスを設定する必要があることにも注意してください。

public class MyClass 
{
    public string ObjectName { get; set; }
    public string Guid { get; set; }
    public string FileName { get; set; }
}

使用可能なクラスがある場合、selectステートメントは次のように変更さselect new { ... }れます。

/* start of query unchanged ... */
select new MyClass
{
    ObjectName = split[0],
    Guid = split[1],
    FileName = f.FullName
};

このすべてのコードを含むメソッドは、戻り型が。になりIEnumerable<MyClass>ます。List<MyClass>を使用すると、簡単にに変更できますreturn results.ToList();

編集#2:ファイル名からobjectNameGuidを抽出するために、内部の詳細から情報を取得するために面倒なXML作業をすべて行う必要はありません。

とが常にスペースで区切られていると仮定するobjectNameと、次のコードを使用できます。Guidそれ以外の場合は、より多くの構文解析(またはオプションで正規表現)が必要になる場合があります。

string path = @"C:\Foo\Bar"; // your path goes here
var dirInfo = new DirectoryInfo(path);

// DirectoryInfo.GetFiles() returns an array of FileInfo[]
// FileInfo's Name property gives us the file's name without the full path
// LINQ let statement stores the split result, splitting the filename on spaces
// and dots to get the objectName, and Guid separated from the file extension.
// The "select new" projects the results into an anonymous type with the specified
// properties and respectively assigned values. I stored the fullpath just in case.
var query = from f in dirInfo.GetFiles("*.xml")
            let split = f.Name.Split(new[] { ' ', '.' })
            select new 
            {
                ObjectName = split[0],
                Guid = split[1],
                FileName = f.FullName
            };

// Now that the above query has neatly separated the ObjectName, we use LINQ
// to group by ObjectName (the group key). Multiple files may exist under the same
// key so we then select the First item from each group.
var results = query.GroupBy(o => o.ObjectName)
                   .Select(g => g.First());

// Iterate over the results using the projected property names.
foreach (var item in results)
{
    Console.WriteLine(item.FileName);
    Console.WriteLine("ObjectName: {0} -- Guid {1}", item.ObjectName, item.Guid);
}

これはサンプルデータに適合しますが、.文字を含むファイル名が予想される場合は、上記が機能しなくなります。このようなシナリオの変更を修正するには、次のようにします。

  1. Splitlet split = f.Name.Split(' ')
  2. ガイド:Guid = split[1].Substring(0, split[1].LastIndexOf('.')),


常にアンダースコアがあることがわかっているので、このアプローチを試すことができます。

string[] arr = {"s_0001", "s_0002", "s_0003", "sa_0004", "sa_0005", "sab_0006", "sab_0007"};

var query = arr.GroupBy(s => s.Substring(0, s.IndexOf('_')))
               .Select(g => g.First());

foreach (string s in query)
    Console.WriteLine(s);    // s_0001, sa_0004, sab_0006

これは各グループの最初のアイテムを取得するため、アイテムが事前に並べ替えられていない限りOrderBySelect:にスローすることをお勧めします。.Select(g => g.OrderBy(s => s).First());

編集:編集に応じて、アンダースコアの前に個別の文字(つまり、s、sa、sab)を取得するには、次のようにEnumerable.Distinctメソッドを使用できます。

var query = arr.Select(s => s.Substring(0, s.IndexOf('_')))
               .Distinct();    // s, sa, sab

これにより、前に示したようIEnumerable<string>にを繰り返し処理できるようになりforeachます。

于 2010-08-23T14:26:22.037 に答える
2
Dictionary<string,string> lettersToRecords = new Dictionary<string,string>();
arr.Foreach((record) =>
    {
        string letters = record.Split('_')[0];
        if(!lettersToRecords.Keys.Contains(letters))
        {
            lettersToRecords[letters] = record;
        }
    });
于 2010-08-23T14:48:51.507 に答える
1

これが私の最初の本能でした:

string[] arr = {"s_0001", "s_0002", "s_0003", "sa_0004", "sa_0005", "sab_0006", "sab_0007"};

arr.Select(a => Regex.Match(a,@"([A-Za-z]+)_([0-9]+)").Groups[1].ToString()).Distinct();
于 2010-08-23T14:38:27.403 に答える
0

arr [0] arr [3] arr [6]

于 2010-08-23T14:12:56.377 に答える
0

string.Split('_')配列内の各文字列で使用できます。

接頭辞を覚えて、その接頭辞を持つ1つの単語を抽出した後、同じ接頭辞を持つすべての単語を無視します。

配列に特定の順序がある場合は、少しでも最適化できます。

于 2010-08-23T14:21:04.557 に答える
0

したがって、基本的に、配列の各要素は、プレフィックス( "s"、 "sa"、 "sab")とサフィックス( "0001"、 "0002"、 "0003"、 "0004"、 "0005")の2つの値を表します。 「0006」、「0007」)。

これは、Linqを使用して文字列をプレフィックスとサフィックスに分割し、プレフィックスに基づいて要素をグループ化する例です。最後のステップでは、グループ化を繰り返して、プレフィックスと、そのプレフィックスで見つかった最初の要素のサフィックスを出力します。

string[] arr = new[] { "s_0001", "s_0002", "s_0003", "sa_0004", "sa_0005", "sab_0006", "sab_0007" };

var elementsByPrefix = arr.Select(s =>
{
    int indexOfUnderscore = s.IndexOf('_');
    if (indexOfUnderscore >= 0)
    {
        return new { Prefix = s.Substring(0, indexOfUnderscore), Suffix = s.Substring(indexOfUnderscore + 1, s.Length - (indexOfUnderscore + 1)) };
    }
    else
    {
        return new { Prefix = s, Suffix = string.Empty };
    }
}).GroupBy(item => item.Prefix);

foreach (var element in elementsByPrefix)
{
    Console.WriteLine("{0}_{1}", element.Key, element.First().Suffix);
}

このコードの出力は、「sab_0007」ではなく「sab_0006」を出力するため、元の質問と完全には一致しませんが、一方と他方を出力するためのルールを実際に指定しなかったため、私はその接頭辞を持つ最初の要素またはその接頭辞を持つ任意の要素のいずれかが必要であると想定します。

于 2010-08-23T14:27:16.793 に答える
0

私が理解できる限り、要素のプレフィックスでセットを区別したいので、次に実行します。

class YourStringComparer : System.Collections.Generic.IEqualityComparer<string[]>
{
    public bool Equals(string[] x, string[] y)
    {
        throw new NotImplementedException(); // not used here
    }

    public int GetHashCode(string[] obj)
    {
        return obj.First().GetHashCode();
    }
}

string[] arr = new[] { "s_0001", "s_0002", "s_0003", "sa_0004", "sa_0005", "sab_0006", "sab_0007" };

var r = arr.Select(s => s.Split('_')).Distinct(new YourStringComparer());
// "s_0001", "sa_0004", "sab_0006"
于 2010-08-23T14:50:43.173 に答える