3
  List<string> allApps = new List<string>();
        roster = MURLEngine.GetUserFriendDetails(token, userId);
        var usersfriends = from elements in roster.RosterEntries
                           where elements[0] == 'm' && elements[1] >= '0' && elements[1] <= '9'
                           select elements;
        foreach (string userid in usersfriends)
        {
            roster = MURLEngine.GetUserFriendDetails(token, userid);
            var usersapps = from elements in roster.RosterEntries
                            where elements[0] != 'm'
                            select elements;
            allApps.AddRange(usersapps);

            allApps = allApps.Distinct().ToList();
        }



        int countapps = 0;
        List<string> Appname = new List<string>();
        countapps = appList.Count();

        for (int y = 0; y < countapps; y++)
        {
            foreach (string li in allApps)  // 
            {
                bool istrueapp = appList.ElementAt(y).AppName.Equals(li);
                if (istrueapp == true)
                {
                    Appname.Add(appList.ElementAt(y).AppName);
                }
            }
        }

上記のコードでは、最初に文字列のリスト、つまりusersfriendsを取得し、次にそれらのIDに基づいて、ユーザーのアプリのリストを取得し、すべてのユーザーのすべてのアプリを別のリスト、つまりallAppsに追加しているため、プロセス全体が遅くなりますリストを使用してこれを実行するには、約 20 秒かかります。HashSet と SortedSet も使用しようとしましたが、さらに遅くなりました。

私の質問は、このシナリオでどのデータ構造を使用する必要があるかです??

本当に助かります

4

4 に答える 4

3

LINQ で私が気に入っている点は、目標を曖昧にするループをたくさん書くのではなく、やりたいことを記述できることです。これはあなたのコードのリファクタリングされたバージョンです。これはかなり明確で、私のテストベッドでより高速に実行されます (0.5 秒対 ~15 秒)。

// create a hashset for fast confirmation of app names
var realAppNames = new HashSet<string>(appList.Select(a => a.AppName));

var roster = MURLEngine.GetUserFriendDetails(token, userId);

// get the ids of all friends
var friendIds = roster.RosterEntries
                      .Where (e => e[0] == 'm' && e[1] >= '0' && e[1] <= '9');

var apps = 
    friendIds 
    // get the rosters for all friends
    .SelectMany (friendId => MURLEngine.GetUserFriendDetails(token, friendId)).RosterEntries)
    // include the original user's roster so we get their apps too
    .Concat(roster.RosterEntries) 
    // filter down to apps only
    .Where (name => name[0] != 'm' && realAppNames.Contains(name)) 
    // remove duplicates
    .Distinct()
    // we're done!
    .ToList();
于 2013-09-28T17:36:51.850 に答える
1

わかりました、これまでのところ何を提案できますか。

まず: がたくさんありAddます。
一般に、デフォルトList<T>は多くの 's に最適なデータ構造ではありません。これはAdd、内部的に配列として実装されており、いっぱいになると破棄されてより大きな配列にコピーされるためです。
2 つのオプションが可能です:
- 定義済み容量でリストを作成: List<string> allApps = new List<string>(countOfApps);. これは、リストに追加するアイテムの数を事前に大まかに計算できる場合に適しています。
-使用LinkedList<string> allApps = new LinkedList<string>()。LinkedList は、新しい項目を非常に高速に追加します。

リストについても同じことが言えList<string> Appname = new List<string>();ます。

第二に:最初に、distinct-edされたリストを取得し、-loopの各反復でリストに変換しますがforeach、新しく構築されたリストはそのループでは使用されません。distinct->tolistしたがって、ここでそのコードをループの外に 移動できます。コード ロジックは変更されませんが、パフォーマンスは向上します。

これまでのところ、次のコードを提案できます。

 LinkedList<string> allApps2 = new LinkedList<string>();// linkedlist here
        roster = MURLEngine.GetUserFriendDetails(token, userId);
        var usersfriends = from elements in roster.RosterEntries
                           where elements[0] == 'm' && elements[1] >= '0' && elements[1] <= '9'
                           select elements;
        foreach (string userid in usersfriends)
        {
            roster = MURLEngine.GetUserFriendDetails(token, userid);
            var usersapps = from elements in roster.RosterEntries
                            where elements[0] != 'm'
                            select elements;
            foreach(var userapp in usersapps)// add _all the apps_ to list. Will be distinct-ed later
            {
                allApps2.AddLast(userapp);// don't worry, it works for O(1)
            }

        }

        var allApps = allApps2.Distinct().ToList();

        int countapps = 0;
        LinkedList<string> Appname2 = new LinkedList<string>();// linkedlist here
        countapps = appList.Count();

        for (int y = 0; y < countapps; y++)
        {
            foreach (string li in allApps)  // 
            {
                bool istrueapp = appList.ElementAt(y).AppName.Equals(li);
                if (istrueapp == true)
                {
                    Appname2.AddLast(appList.ElementAt(y).AppName);// and here
                }
            }
        }

        var AppName = Appname2.ToList();// and you've got you List<string> as the result

このコードを試して、どのように動作するか教えてください (かなり速く動作するはずですが)。お役に立てれば。

更新
やっと家に帰ってきました、遅れてすみません。私はコードを少しいじって、最後forにこれに書き直して高速化しました:

foreach (var app in appList)
            {
                foreach (string li in allApps) 
                {
                    bool istrueapp = app.AppName.Equals(li);
                    if (istrueapp)
                    {
                        Appname2.AddLast(app.AppName);
                    }
                }
            }

これにより、少なくとも私のマシン(r)では、大幅なスピードアップが得られました。
お使いの環境で高速になるかどうかを確認してください。
それが役立つことを願っています。

于 2013-09-17T20:39:36.817 に答える
0

別の回答で既にコメントしたように、List多数の要素を処理し、単純なアクションを実行する場合、 a はあまり効率的ではありません。より単純なコレクション (例: Array) は、これらの条件下でより効率的なソリューションを表します。サンプル コード (「プレーンな」配列を処理するように調整されています。現在のリストまたは配列を使用し始める場合に使用できます):

List<string> Appname = new List<string>();
roster = MURLEngine.GetUserFriendDetails(token, userId);
foreach (string item in roster.RosterEntries)
{
    if(item == null || item.Trim().Length < 1) continue;
    if (item[0] == 'm' && Convert.ToInt32(item[1]) >= 0 && Convert.ToInt32(item[1]) <= 9)
    {
        var roster2 = MURLEngine.GetUserFriendDetails(token, item);
        foreach (string item2 in roster2.RosterEntries)
        {
            if(item2 == null || item2.Trim().Length < 1) continue;
            if (item2[0] != 'm')
            {
                bool found = false;
                foreach (string app in appList)
                {
                    if(app == null || app.Trim().Length < 1) continue;
                    if (app.AppName == item2)
                    {
                        found = true;
                        break;
                    }
                }
                if (found) Appname.Add(item2);
            }
        }
    }
}

ご覧のとおり、中間ストレージを無視しましたallApps(クエリを介してバージョンで実行することもできます)。

このコードは、元のバージョンに対して顕著な改善をもたらすはずです (主にリストを配列に変換する場合)。このコードをさらに高速化することに関心がある場合は、入力が提供される方法を再設計するオプションを検討する必要があります (したがって、おそらく最も時間がかかる部分であるMURLEngine.GetUserFriendDetails2 回の呼び出しを回避します)。最後に、を List/Array に 格納することで(string app in appList) loop、 を単純な条件 ( ) に置き換えることができることに注意してください。AppNames.Contains(item2)AppNames

于 2013-09-23T19:34:06.457 に答える