zoukankan      html  css  js  c++  java
  • 用C#开发的一个通用的地铁换乘查询工具

    日常生活中,上班下班坐地铁已经是常事,每当我想去某一个远一点的地方,如果有地铁首选就是地铁,因为方便嘛!每次坐地铁,我们都是凭肉眼去得出我们心中最佳的换乘方案,但是,如果对于线路较少的城市来说,这个方法是最快的,但是如果对于线路较多的城市,例如北京或者上海,十几条线路交叉穿梭,我们可能看到都晕了,怎么坐才是时间最短路程最短的,我们要算出来不是不可以但是很麻烦,我们也可以想一想,百度地图的地铁换乘算法是怎么实现的,于是,闲着没事,我就想写一个通用的地铁换乘查询程序,想用计算机运算得出科学一点的换乘方案供自己参考,假设先不考虑站点间的距离差异,我们以乘坐站点数最少为最优方案,依照这个条件去编码实现查找的算法,其实也没用上什么高大上的算法,因为也不会哈哈,话不多说,先上效果图:

    3.png

    有对应城市的线路图(支持鼠标滚轮放大缩小):

    2.png

    站点智能提示:

    5.png

    项目结构图:

    7.png

    我的开发思路:

    1、采用xml存储站点数据,如下:

    6.png

    2、代码中使用集合初始化线路数据

     1 /// <summary>
     2         /// 初始化地铁线路数据
     3         /// </summary>
     4         /// <param name="city">城市</param>
     5         public static void InitSubwayLine(CityEnum city)
     6         {
     7             if (AllSubwayLines != null && AllSubwayLines.Any() && _currentCity == city) return;
     8             _currentCity = city;
     9             var xmlName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xml/" + city.ToString() + ".xml");
    10             _doc = XDocument.Load(xmlName);
    11             AllSubwayLines = _doc.Root.Elements().Select(x =>
    12             {
    13                 var line = new SubwayLine
    14                 {
    15                     No = x.Attribute("No").Value,
    16                     Name = x.Attribute("Name").Value,
    17                     IsRound = x.Attribute("IsRound") == null ? false : bool.Parse(x.Attribute("IsRound").Value),
    18                     Stations = x.Elements().Select((y, i) => new Station
    19                     {
    20                         Index = i,
    21                         Name = y.Attribute("Name").Value,
    22                         LineNo = x.Attribute("No").Value,
    23                         CanTransfer = y.Attribute("CanTransfer") == null ? false : bool.Parse(y.Attribute("CanTransfer").Value),
    24                         TransferNo = y.Attribute("TransferNo") == null ? null : y.Attribute("TransferNo").Value
    25                     }).ToList()
    26                 };
    27                 var translines = line.GetTransStations().Select(z => z.TransferNo.Split(',')).ToList();
    28                 foreach (var transline in translines)
    29                 {
    30                     foreach (var li in transline)
    31                     {
    32                         line.TransferLines.Add(li);
    33                     }
    34                 }
    35                 line.TransferLines = line.TransferLines.Distinct().ToList();
    36                 return line;
    37             }).ToList();
    38         }

    3、分多种情况进行处理,核心代码(代码有点长,我也在想方法浓缩代码,还望各位看官耐心(┬_┬)):

      1         /// <summary>
      2         /// 获取地铁乘车信息
      3         /// </summary>
      4         /// <param name="depStation">出发站</param>
      5         /// <param name="destStation">到达站</param>
      6         /// <param name="city">所在城市</param>
      7         /// <returns>返回各种换乘方案</returns>
      8         public static List<QueryResult> GetRideSubwayInfo(string depStation, string destStation, CityEnum city)
      9         {
     10             InitSubwayLine(city);
     11             if (string.IsNullOrWhiteSpace(depStation) || string.IsNullOrWhiteSpace(destStation)
     12                 || !AllSubwayLines.Exists(x => x.Stations.Exists(y => y.Name.Equals(depStation)))
     13                 || !AllSubwayLines.Exists(x => x.Stations.Exists(y => y.Name.Equals(destStation))))
     14                 return null;//出发站或到达站在线路上不存在!
     15 
     16             //各种换乘提示
     17             //同一条线路
     18             var msg_oneline = "在{0}【{1}】上车,经过{2}站到达目的站【{3}】。
    具体线路为:
    (出发){4}(到达)
    总搭乘站点数:{5}
    ";
     19             //换乘1次
     20             var msg_transOnce = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站到达目的站【{6}】。
    具体线路为:
    (出发){7}(此处换乘{4})-->{8}(到达)
    总搭乘站点数:{9}
    ";
     21             //换乘2次
     22             var msg_transTwice = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站到达目的站【{9}】。
    具体线路为:
    (出发){10}(此处换乘{4})-->{11}(此处换乘{7})-->{12}(到达)
    总搭乘站点数:{13}
    ";
     23             //换乘3次
     24             var msg_transThreetimes = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站在【{9}】下车,换乘{10},经过{11}站到达目的站【{12}】。"
     25                 + "
    具体线路为:
    (出发){13}(此处换乘{4})-->{14}(此处换乘{7})-->{15}(此处换乘{10})-->{16}(到达)
    总搭乘站点数:{17}
    ";
     26             //换乘4次
     27             var msg_transFourtimes = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站在【{9}】下车,换乘{10},经过{11}站在【{12}】下车,换乘{13},经过{14}站到达目的站【{15}】。"
     28                 + "
    具体线路为:
    (出发){16}(此处换乘{4})-->{17}(此处换乘{7})-->{18}(此处换乘{10})-->{19}(此处换乘{13})-->{20}(到达)
    总搭乘站点数:{21}
    ";
     29 
     30             //保存各种换乘方案
     31             var result = new List<QueryResult>();
     32             //第一步:先查找始发站和到达站在哪一条线路
     33             var afterDepLines = GetAcrossLines(depStation);
     34             var afterDestLines = GetAcrossLines(destStation);
     35             //根据同一条线和不同线路展开分析
     36             if (IsSameLine(depStation, destStation))
     37             {
     38                 #region 同一条线路
     39                 var commLines = afterDepLines.Where(x => afterDestLines.Select(y => y.No).Contains(x.No)).ToList();
     40                 //判断线路是否相同,相同直接计算站点距离
     41                 var depIndex = GetIndexOnLine(depStation, commLines.First());
     42                 var destIndex = GetIndexOnLine(destStation, commLines.First());
     43                 var crossStations = commLines.First().Stations.Between(depIndex, destIndex).Select(x => x.Name).ToList();
     44                 var range = crossStations.Count - 1;
     45                 if (depIndex > destIndex) crossStations.Reverse();
     46                 var rs = msg_oneline.FormatTo(commLines.First().ToString(), depStation, range, destStation,
     47                          crossStations.ToJoinString(), range);
     48                 result.Add(new QueryResult() { Description = rs, Range = range });
     49                 #endregion
     50             }
     51             else
     52             {
     53                 #region 不同线路
     54                 if (!IsTransferStation(depStation) && !IsTransferStation(destStation))//如果始发站和终点站都不是换乘站,则表示始发站和到达站都是只有一条线路通过
     55                 {
     56                     if (afterDepLines.First().IsIntersect(afterDestLines.First()))
     57                     {
     58                         #region 如果两条线路交叉,一定有换乘站点
     59                         var clist = GetAcrossStations(afterDepLines.First(), afterDestLines.First()).Select(x => x.Name).ToList();
     60                         var i = GetIndexOnLine(depStation, afterDepLines.First());
     61                         var j = GetIndexOnLine(clist.First(), afterDepLines.First());
     62                         var k = GetIndexOnLine(destStation, afterDestLines.First());
     63                         var l = GetIndexOnLine(clist.First(), afterDestLines.First());
     64                         var coss1 = afterDepLines.First().Stations.Between(i, j).Select(x => x.Name).ToList();
     65                         var coss2 = afterDestLines.First().Stations.Between(k, l).Select(x => x.Name).ToList();
     66                         if (i > j) coss1.Reverse();
     67                         if (k < l) coss2.Reverse();
     68                         var rang1 = coss1.Count - 1;
     69                         var rang2 = coss2.Count - 1;
     70                         var h = rang1 + rang2; //站点数
     71                         var rs = msg_transOnce.FormatTo(afterDepLines.First().ToString(), depStation, rang1, clist.First(),
     72                             afterDestLines.First().ToString(), rang2, destStation,
     73                             coss1.ToJoinString(), coss2.Where(x => x != clist.First()).ToJoinString(), h);
     74                         result.Add(new QueryResult()
     75                         {
     76                             Description = rs,
     77                             Range = h,
     78                             TransferStations = new List<string>() { clist.First() },
     79                             TransferTimes = 1
     80                         });
     81                         #endregion
     82                     }
     83                     else
     84                     {
     85                         #region 不交叉,需要通过第三条线路换乘,即多次换乘
     86                         var depSta = GetStation(depStation);
     87                         var destSta = GetStation(destStation);
     88                         //找出两条线路的可换乘站点,找出可换乘相同线路的站点
     89                         var trans1 = afterDepLines.First().GetTransStations();
     90                         var trans2 = afterDestLines.First().GetTransStations();
     91                         var trans3 = new List<Station>();
     92                         var trans4 = new List<Station>();
     93                         var expets = trans1.Join(trans2, x => x.TransferNo, y => y.TransferNo, (x, y) =>
     94                         {
     95                             trans3.Add(x);
     96                             trans4.Add(y);
     97                             return x.Name + "---" + y.Name;
     98                         }).ToList();
     99                         if (expets.Any())
    100                         {
    101                             #region 两次换乘
    102                             //trans3.Count和trans4.Count必定相等
    103                             //计算最短距离,列出所有换乘方案
    104                             for (var i = 0; i < trans3.Count; i++)
    105                             {
    106                                 var tranLine = GetLine(trans3[i].TransferNo);
    107                                 //获取这两个站点在此线路的索引                   
    108                                 var ix1 = depSta.Index;
    109                                 var ix2 = destSta.Index;
    110                                 var iix1 = GetIndexOnLine(trans3[i].Name, depSta.LineNo);
    111                                 var iix2 = GetIndexOnLine(trans4[i].Name, destSta.LineNo);
    112                                 var tx1 = GetIndexOnLine(trans3[i].Name, tranLine);
    113                                 var tx2 = GetIndexOnLine(trans4[i].Name, tranLine);
    114 
    115                                 var depRange = afterDepLines.First().Stations.Between(ix1, iix1).Select(x => x.Name).ToList();
    116                                 var destRange = afterDestLines.First().Stations.Between(ix2, iix2).Select(x => x.Name).ToList();
    117                                 var transRange = tranLine.Stations.Between(tx1, tx2).Select(x => x.Name).ToList();
    118                                 if (ix1 > iix1) depRange.Reverse();
    119                                 if (ix2 < iix2) destRange.Reverse();
    120                                 if (tx1 > tx2) transRange.Reverse();
    121                                 var r1 = depRange.Count - 1;
    122                                 var r2 = destRange.Count - 1;
    123                                 var r3 = transRange.Count - 1;
    124                                 var r = r1 + r2 + r3;
    125                                 var rs = msg_transTwice.FormatTo(afterDepLines.First().ToString(), depStation, r1,
    126                                     trans3[i].Name,
    127                                     tranLine.ToString(), r3, trans4[i].Name, afterDestLines.First().ToString(), r2,
    128                                     destStation, depRange.ToJoinString(),
    129                                         transRange.Where(x => !x.IsSame(trans3[i].Name) && !x.IsSame(trans4[i].Name)).ToJoinString(),
    130                                      destRange.ToJoinString(), r);
    131                                 result.Add(new QueryResult()
    132                                 {
    133                                     Description = rs,
    134                                     Range = r,
    135                                     TransferTimes = 2,
    136                                     TransferStations = new List<string>() { trans3[i].Name, trans4[i].Name }
    137                                 });
    138                             }
    139                             #endregion
    140                         }
    141                         #region 查找3次以上换乘的可能结果,寻求最短距离
    142                         var trlines1 = afterDepLines.First().TransferLines.Select(GetLine).ToList();
    143                         var trlines2 = afterDestLines.First().TransferLines.Select(GetLine).ToList();
    144                         var destss = new List<Station>();
    145 
    146                         #region 换乘3次
    147                         foreach (var depline in trlines1)
    148                         {
    149                             foreach (var destline in trlines2)
    150                             {
    151                                 var ss = destline.GetAcrossStations(depline);
    152                                 if (!ss.Any()) continue; //3次换乘
    153                                 var slist1 = afterDepLines.First().GetAcrossStations(depline);
    154                                 if (!slist1.Any()) continue;
    155                                 var s1 = slist1.GetClosestStation(depSta.Name);
    156                                 var s1_ix1 = depSta.Index;
    157                                 var s1_ix2 = s1.Index;
    158                                 var s1_range =
    159                                     afterDepLines.First()
    160                                         .Stations.Between(s1_ix1, s1_ix2)
    161                                         .Select(x => x.Name)
    162                                         .ToList();
    163                                 var s1_h = s1_range.Count - 1;
    164                                 if (s1_ix1 > s1_ix2) s1_range.Reverse();
    165 
    166                                 var s2_ix1 = GetIndexOnLine(s1.Name, depline);
    167                                 var s2_ix2 = GetIndexOnLine(ss.First().Name, depline);
    168                                 var s2_range = depline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList();
    169                                 var s2_h = s2_range.Count - 1;
    170                                 if (s2_ix1 > s2_ix2) s2_range.Reverse();
    171 
    172                                 var slist3 = destline.GetAcrossStations(afterDestLines.First());
    173                                 if (!slist3.Any()) continue;
    174                                 var s3 = slist3.GetClosestStation(ss.First().Name);
    175                                 var s3_ix1 = s3.Index;
    176                                 var s3_ix2 = ss.First().Index;
    177                                 var s3_range = destline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList();
    178                                 var s3_h = s3_range.Count - 1;
    179                                 if (s3_ix1 < s3_ix2) s3_range.Reverse();
    180 
    181                                 var s4_ix1 = GetIndexOnLine(s3.Name, afterDestLines.First());
    182                                 var s4_ix2 = destSta.Index;
    183                                 var s4_range =
    184                                     afterDestLines.First()
    185                                         .Stations.Between(s4_ix1, s4_ix2)
    186                                         .Select(x => x.Name)
    187                                         .ToList();
    188                                 var s4_h = s4_range.Count - 1;
    189                                 if (s4_ix1 > s4_ix2) s4_range.Reverse();
    190 
    191                                 var h = s1_h + s2_h + s3_h + s4_h;
    192                                 var rs = msg_transThreetimes.FormatTo(afterDepLines.First().ToString(), depStation,
    193                                     s1_h, s1.Name,
    194                                     depline.ToString(), s2_h, ss.First().Name,
    195                                     GetLine(ss.First().LineNo).ToString(), s3_h, s3.Name,
    196                                     afterDestLines.First().ToString(), s4_h, destStation, s1_range.ToJoinString(),
    197                                     s2_range.Where(x => x != s1.Name).ToJoinString(),
    198                                     s3_range.Where(x => x != ss.First().Name).ToJoinString(),
    199                                     s4_range.Where(x => x != s3.Name).ToJoinString(), h);
    200                                 result.Add(new QueryResult()
    201                                 {
    202                                     Description = rs,
    203                                     Range = h,
    204                                     TransferTimes = 3,
    205                                     TransferStations =
    206                                         new List<string>()
    207                                         {
    208                                                         s1.Name,
    209                                                         ss.First().Name,
    210                                                         s3.Name
    211                                         }
    212                                 });
    213                                 destss.AddRange(ss);
    214                             }
    215                         }
    216                         #endregion
    217 
    218                         if (!destss.Any()) //换乘4次
    219                         {
    220                             #region 换乘4次
    221                             foreach (var depline in trlines1)
    222                             {
    223                                 foreach (var destline in trlines2)
    224                                 {
    225                                     var deptrlines =
    226                                         depline.TransferLines.Where(x => x != afterDepLines.First().No)
    227                                             .Select(GetLine)
    228                                             .ToList();
    229                                     foreach (var line in deptrlines)
    230                                     {
    231                                         var s1 = line.GetAcrossStations(destline);
    232                                         if (!s1.Any()) continue; //4次换乘
    233                                         var trlist1 = afterDepLines.First().GetAcrossStations(depline);
    234                                         if (!trlist1.Any()) continue;
    235                                         var tr1 = trlist1.GetClosestStation(depSta.Name);
    236                                         var s1_ix1 = depSta.Index;
    237                                         var s1_ix2 = tr1.Index;
    238                                         var s1_range =
    239                                             afterDepLines.First()
    240                                                 .Stations.Between(s1_ix1, s1_ix2)
    241                                                 .Select(x => x.Name)
    242                                                 .ToList();
    243                                         var h1 = s1_range.Count - 1;
    244                                         if (s1_ix1 > s1_ix2) s1_range.Reverse();
    245 
    246                                         var trlist2 = GetLine(tr1.TransferNo).GetAcrossStations(line);
    247                                         if (!trlist2.Any()) continue;
    248                                         var tr2 = trlist2.GetClosestStation(tr1.Name);
    249                                         var s2_ix1 = GetIndexOnLine(tr1.Name, depline);
    250                                         var s2_ix2 = tr2.Index;
    251                                         var s2_range =
    252                                             depline.Stations.Between(s2_ix1, s2_ix2)
    253                                                 .Select(x => x.Name)
    254                                                 .ToList();
    255                                         var h2 = s2_range.Count - 1;
    256                                         if (s2_ix1 > s2_ix2) s2_range.Reverse();
    257 
    258                                         var s3_ix1 = GetIndexOnLine(tr2.Name, line);
    259                                         var s3_ix2 = s1.First().Index;
    260                                         var s3_range =
    261                                             line.Stations.Between(s3_ix1, s3_ix2)
    262                                                 .Select(x => x.Name)
    263                                                 .ToList();
    264                                         var h3 = s3_range.Count - 1;
    265                                         if (s3_ix1 > s3_ix2) s3_range.Reverse();
    266 
    267                                         var trlist3 = destline.GetAcrossStations(afterDestLines.First());
    268                                         if (!trlist3.Any()) continue;
    269                                         var tr3 = trlist3.GetClosestStation(s1.First().Name);
    270                                         var s4_ix1 = GetIndexOnLine(s1.First().Name, destline);
    271                                         var s4_ix2 = tr3.Index;
    272                                         var s4_range =
    273                                             destline.Stations.Between(s4_ix1, s4_ix2)
    274                                                 .Select(x => x.Name)
    275                                                 .ToList();
    276                                         var h4 = s4_range.Count - 1;
    277                                         if (s4_ix1 > s4_ix2) s4_range.Reverse();
    278 
    279                                         var s5_ix1 = GetIndexOnLine(tr3.Name, afterDestLines.First());
    280                                         var s5_ix2 = destSta.Index;
    281                                         var s5_range =
    282                                             afterDestLines.First()
    283                                                 .Stations.Between(s5_ix1, s5_ix2)
    284                                                 .Select(x => x.Name)
    285                                                 .ToList();
    286                                         var h5 = s5_range.Count - 1;
    287                                         if (s5_ix1 > s5_ix2) s5_range.Reverse();
    288                                         var h = h1 + h2 + h3 + h4 + h5;
    289                                         var rs =
    290                                             msg_transFourtimes.FormatTo(afterDepLines.First().ToString(),
    291                                                 depStation, h1, tr1.Name,
    292                                                 depline.ToString(), h2, tr2.Name,
    293                                                 line.ToString(), h3, s1.First().Name,
    294                                                 destline.ToString(), h4, tr3.Name,
    295                                                afterDestLines.First().ToString(), h5, destStation,
    296                                                 s1_range.ToJoinString(),
    297                                                 s2_range.Where(x => x != tr1.Name).ToJoinString(),
    298                                                 s3_range.Where(x => x != tr2.Name).ToJoinString(),
    299                                                 s4_range.Where(x => x != tr2.Name && x != s1.First().Name).ToJoinString(),
    300                                                 s5_range.Where(x => x != tr3.Name).ToJoinString(), h);
    301                                         result.Add(new QueryResult()
    302                                         {
    303                                             Description = rs,
    304                                             Range = h,
    305                                             TransferTimes = 4,
    306                                             TransferStations =
    307                                                 new List<string>()
    308                                                 {
    309                                                             tr1.Name,
    310                                                             tr2.Name,
    311                                                             s1.First().Name,
    312                                                             tr3.Name
    313                                                 }
    314                                         });
    315                                         destss.AddRange(s1);
    316                                     }
    317                                 }
    318                             }
    319                             #endregion
    320                         }
    321                         if (!destss.Any())//换乘4次以上
    322                         {
    323 
    324                         }
    325                         #endregion
    326                         #endregion
    327                     }
    328                 }
    329                 else //始发站和到达站有其中一个是换乘站
    330                 {
    331                     //找出到达站经过的路线和始发站所在路线的交叉线路
    332                     var crossLines = GetAcrossLines(depStation, destStation);
    333                     //分三种情况:1、始发站不是换乘站而到达站是换乘站;2、始发站是换乘站而到达站不是换乘站;3、始发站和到达站都是换乘站,根据情况展开分析
    334                     if (!IsTransferStation(depStation) && IsTransferStation(destStation))
    335                     {
    336                         #region 情况1:始发站不是换乘站而到达站是换乘站
    337                         if (crossLines.Count > 0) //依赖交叉线
    338                         {
    339                             var listTrans = new List<Station>();
    340                             foreach (var line in crossLines)
    341                             {
    342                                 //找出每条交叉线换乘到始发站线路的所有换乘站
    343                                 var ss = line.GetTransStations()
    344                                         .Where(x => x.TransferNo.IsSame(afterDepLines.First().No))
    345                                         .ToList();
    346                                 listTrans.AddRange(ss);
    347                             }
    348                             var depIx = GetIndexOnLine(depStation, afterDepLines.First());
    349                             var tranStas =
    350                                 listTrans.Select(
    351                                         s => new { sta = s, ix = GetIndexOnLine(s.Name, afterDepLines.First()) })
    352                                     .ToList();
    353                             foreach (var sta in tranStas)
    354                             {
    355                                 var destIx = GetIndexOnLine(destStation, sta.sta.LineNo);
    356                                 var tranIx = GetIndexOnLine(sta.sta.Name, sta.sta.LineNo);
    357                                 var coss1 =
    358                                     afterDepLines.First()
    359                                         .Stations.Between(depIx, sta.ix)
    360                                         .Select(x => x.Name)
    361                                         .ToList();
    362                                 var coss2 =
    363                                     GetLine(sta.sta.LineNo)
    364                                         .Stations.Between(destIx, tranIx)
    365                                         .Select(x => x.Name)
    366                                         .ToList();
    367                                 var rang1 = coss1.Count - 1;
    368                                 var rang2 = coss2.Count - 1;
    369                                 var h = rang1 + rang2; //站点数
    370                                 if (depIx > sta.ix) coss1.Reverse();
    371                                 if (destIx < tranIx) coss2.Reverse();
    372 
    373                                 var rs = msg_transOnce.FormatTo(afterDepLines.First().ToString(), depStation, rang1,
    374                                     sta.sta.Name,
    375                                     GetLine(sta.sta.LineNo).ToString(), rang2, destStation,
    376                                     coss1.ToJoinString(), coss2.Where(x => x != sta.sta.Name).ToJoinString(), h);
    377                                 result.Add(new QueryResult()
    378                                 {
    379                                     Description = rs,
    380                                     Range = h,
    381                                     TransferTimes = 1,
    382                                     TransferStations = new List<string>() { sta.sta.Name }
    383                                 });
    384                             }
    385                         }
    386                         //查找其他换乘可能
    387                         var depSta = GetStation(depStation);
    388                         var trlinesDep = afterDepLines.First().TransferLines.Select(GetLine).ToList();
    389                         foreach (var depline in afterDestLines)
    390                         {
    391                             var trlineItems = depline.TransferLines.Select(GetLine).ToList();
    392                             foreach (var iline in trlineItems)
    393                             {
    394                                 foreach (var destline in trlinesDep)
    395                                 {
    396                                     var ss = destline.GetAcrossStations(iline);
    397                                     if (!ss.Any()) continue; //3次换乘
    398                                     var slist1 = afterDepLines.First().GetAcrossStations(destline);
    399                                     if (!slist1.Any()) continue;
    400                                     var s1 = slist1.GetClosestStation(depStation);
    401                                     var s1_ix1 = depSta.Index;
    402                                     var s1_ix2 = s1.Index;
    403 
    404                                     var s1_range =
    405                                         afterDepLines.First()
    406                                             .Stations.Between(s1_ix1, s1_ix2)
    407                                             .Select(x => x.Name)
    408                                             .ToList();
    409                                     var s1_h = s1_range.Count - 1;
    410                                     if (s1_ix1 > s1_ix2) s1_range.Reverse();
    411 
    412                                     var s2 = ss.GetClosestStation(s1.Name);
    413                                     var s2_ix1 = GetIndexOnLine(s1.Name, destline);
    414                                     var s2_ix2 = GetIndexOnLine(s2.Name, destline);
    415                                     var s2_range = destline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList();
    416                                     var s2_h = s2_range.Count - 1;
    417                                     if (s2_ix1 > s2_ix2) s2_range.Reverse();
    418 
    419                                     var slist3 = iline.GetAcrossStations(depline);
    420                                     if (!slist3.Any()) continue;
    421                                     var s3 = slist3.GetClosestStation(s2.Name);
    422                                     var s3_ix1 = s3.Index;
    423                                     var s3_ix2 = GetIndexOnLine(s2.Name, iline);
    424                                     var s3_range = iline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList();
    425                                     var s3_h = s3_range.Count - 1;
    426                                     if (s3_ix1 < s3_ix2) s3_range.Reverse();
    427 
    428                                     var s4_ix1 = GetIndexOnLine(s3.Name, depline);
    429                                     var s4_ix2 = GetIndexOnLine(destStation, depline);
    430                                     var s4_range = depline.Stations.Between(s4_ix1, s4_ix2)
    431                                         .Select(x => x.Name)
    432                                         .ToList();
    433                                     var s4_h = s4_range.Count - 1;
    434                                     if (s4_ix1 > s4_ix2) s4_range.Reverse();
    435 
    436                                     var h = s1_h + s2_h + s3_h + s4_h;
    437                                     if (s2_h == 0 || s3_h == 0 || s4_h == 0 || destline.No.IsSame(iline.No)) continue;
    438                                     var rs = msg_transThreetimes.FormatTo(afterDepLines.First().ToString(),
    439                                         depStation,
    440                                         s1_h, s1.Name,
    441                                         destline.ToString(), s2_h, s2.Name,
    442                                         iline.ToString(), s3_h, s3.Name,
    443                                         depline.ToString(), s4_h, destStation, s1_range.ToJoinString(),
    444                                         s2_range.Where(x => x != s1.Name).ToJoinString(),
    445                                         s3_range.Where(x => x != s2.Name).ToJoinString(),
    446                                         s4_range.Where(x => x != s3.Name).ToJoinString(), h);
    447                                     result.Add(new QueryResult()
    448                                     {
    449                                         Description = rs,
    450                                         Range = h,
    451                                         TransferTimes = 3,
    452                                         TransferStations =
    453                                             new List<string>()
    454                                             {
    455                                                     s1.Name,
    456                                                     s2.Name,
    457                                                     s3.Name
    458                                             }
    459                                     });
    460                                 }
    461                             }
    462                         }
    463                         #endregion
    464                     }
    465                     if (IsTransferStation(depStation) && !IsTransferStation(destStation))
    466                     {
    467                         #region 情况2:始发站是换乘站而到达站不是换乘站
    468                         var transLines =
    469                             afterDepLines.Where(
    470                                     x =>
    471                                         x.Stations.Exists(
    472                                             y => y.CanTransfer && y.TransferNo.Contains(afterDestLines.First().No)))
    473                                 .ToList();
    474                         if (transLines.Any())
    475                         {
    476                             var clist =
    477                                 GetAcrossStations(transLines.First(), afterDestLines.First())
    478                                     .Select(x => x.Name)
    479                                     .ToList();
    480                             var i = GetIndexOnLine(depStation, transLines.First());
    481                             var j = GetIndexOnLine(clist.First(), transLines.First());
    482                             var k = GetIndexOnLine(destStation, afterDestLines.First());
    483                             var l = GetIndexOnLine(clist.First(), afterDestLines.First());
    484                             var coss1 = transLines.First().Stations.Between(i, j).Select(x => x.Name).ToList();
    485                             var coss2 = afterDestLines.First().Stations.Between(k, l).Select(x => x.Name).ToList();
    486                             var rang1 = coss1.Count - 1;
    487                             var rang2 = coss2.Count - 1;
    488                             var h = rang1 + rang2; //站点数
    489                             if (i > j) coss1.Reverse();
    490                             if (k < l) coss2.Reverse();
    491 
    492                             var rs = msg_transOnce.FormatTo(transLines.First().ToString(), depStation, rang1,
    493                                 clist.First(),
    494                                 afterDestLines.First().ToString(), rang2, destStation,
    495                                 coss1.ToJoinString(), coss2.Where(x => x != clist.First()).ToJoinString(), h);
    496                             result.Add(new QueryResult()
    497                             {
    498                                 Description = rs,
    499                                 Range = h,
    500                                 TransferTimes = 1,
    501                                 TransferStations = new List<string>() { clist.First() }
    502                             });
    503                         }
    504                         //寻找其他换乘可能
    505                         var destSta = GetStation(destStation);
    506                         var trlinesDest = afterDestLines.First().TransferLines.Select(GetLine).ToList();
    507                         foreach (var depline in afterDepLines)
    508                         {
    509                             var trlineItems = depline.TransferLines.Select(GetLine).ToList();
    510                             foreach (var iline in trlineItems)
    511                             {
    512                                 foreach (var destline in trlinesDest)
    513                                 {
    514                                     var ss = iline.GetAcrossStations(destline);
    515                                     if (!ss.Any()) continue; //3次换乘
    516                                     var slist1 = depline.GetAcrossStations(iline);
    517                                     if (!slist1.Any()) continue;
    518                                     var s1 = slist1.GetClosestStation(depStation);
    519                                     var s1_ix1 = GetIndexOnLine(depStation, depline);
    520                                     var s1_ix2 = s1.Index;
    521                                     var s1_range =
    522                                         depline.Stations.Between(s1_ix1, s1_ix2)
    523                                             .Select(x => x.Name)
    524                                             .ToList();
    525                                     var s1_h = s1_range.Count - 1;
    526                                     if (s1_ix1 > s1_ix2) s1_range.Reverse();
    527 
    528                                     var s2 = ss.GetClosestStation(s1.Name);
    529                                     var s2_ix1 = GetIndexOnLine(s1.Name, iline);
    530                                     var s2_ix2 = GetIndexOnLine(s2.Name, iline);
    531                                     var s2_range = iline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList();
    532                                     var s2_h = s2_range.Count - 1;
    533                                     if (s2_ix1 > s2_ix2) s2_range.Reverse();
    534 
    535                                     var slist3 = destline.GetAcrossStations(afterDestLines.First());
    536                                     if (!slist3.Any()) continue;
    537                                     var s3 = slist3.GetClosestStation(ss.First().Name);
    538                                     var s3_ix1 = s3.Index;
    539                                     var s3_ix2 = GetIndexOnLine(s2.Name, destline);
    540                                     var s3_range = destline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList();
    541                                     var s3_h = s3_range.Count - 1;
    542                                     if (s3_ix1 < s3_ix2) s3_range.Reverse();
    543 
    544                                     var s4_ix1 = GetIndexOnLine(s3.Name, afterDestLines.First());
    545                                     var s4_ix2 = destSta.Index;
    546                                     var s4_range =
    547                                         afterDestLines.First()
    548                                             .Stations.Between(s4_ix1, s4_ix2)
    549                                             .Select(x => x.Name)
    550                                             .ToList();
    551                                     var s4_h = s4_range.Count - 1;
    552                                     if (s4_ix1 > s4_ix2) s4_range.Reverse();
    553 
    554                                     var h = s1_h + s2_h + s3_h + s4_h;
    555                                     if (s1_h == 0 || s2_h == 0 || s3_h == 0 || iline.No.IsSame(destline.No)) continue;
    556                                     var rs = msg_transThreetimes.FormatTo(depline.ToString(), depStation,
    557                                         s1_h, s1.Name,
    558                                         iline.ToString(), s2_h, s2.Name,
    559                                         destline.ToString(), s3_h, s3.Name,
    560                                         afterDestLines.First().ToString(), s4_h, destStation,
    561                                         s1_range.ToJoinString(),
    562                                         s2_range.Where(x => x != s1.Name).ToJoinString(),
    563                                         s3_range.Where(x => x != s2.Name).ToJoinString(),
    564                                         s4_range.Where(x => x != s3.Name).ToJoinString(), h);
    565                                     result.Add(new QueryResult()
    566                                     {
    567                                         Description = rs,
    568                                         Range = h,
    569                                         TransferTimes = 3,
    570                                         TransferStations =
    571                                             new List<string>()
    572                                             {
    573                                                     s1.Name,
    574                                                     s2.Name,
    575                                                     s3.Name
    576                                             }
    577                                     });
    578                                 }
    579                             }
    580                         }
    581                         #endregion
    582                     }
    583                     if (IsTransferStation(depStation) && IsTransferStation(destStation))
    584                     {
    585                         #region 情况3:始发站和到达站都是换乘站
    586                         if (crossLines.Count > 0) //依赖交叉线
    587                         {
    588                             var transStations = GetClosestStation(depStation, true);
    589                             if (
    590                                 !transStations.Exists(
    591                                     x =>
    592                                         crossLines.Exists(y => y.Stations.Exists(z => x.TransferNo.Split(',').Intersect(z.LineNo.Split(',')).Any()))))
    593                             {
    594                                 transStations = new List<Station>();
    595                                 afterDepLines.ForEach(x =>
    596                                 {
    597                                     var ctrans = x.GetTransStations();
    598                                     var ctrans2 =
    599                                         ctrans.Where(
    600                                                 y =>
    601                                                     crossLines.Exists(
    602                                                         z => z.Stations.Exists(zz => y.TransferNo.Split(',').Intersect(zz.LineNo.Split(',')).Any())))
    603                                             .ToList();
    604                                     transStations.AddRange(ctrans2);
    605                                 });
    606                             }
    607                             var transLine =
    608                                 afterDestLines.Where(
    609                                         x =>
    610                                             x.Stations.Exists(y => transStations.Exists(z => z.Name.IsSame(y.Name))))
    611                                     .ToList();
    612                             var intersStas =
    613                                 transStations.Where(
    614                                         x =>
    615                                             transLine.Exists(
    616                                                 y =>
    617                                                     y.Stations.Exists(
    618                                                         z => z.Name.IsSame(x.Name) && x.TransferNo.Split(',').Intersect(z.LineNo.Split(',')).Any())))
    619                                     .ToList();
    620                             foreach (var line in transLine)
    621                             {
    622                                 //分别获取换乘站在换乘线上的索引
    623                                 foreach (var t in intersStas)
    624                                 {
    625                                     var ix = GetIndexOnLine(destStation, line); //目的站在换乘线上的索引
    626                                     var iix = GetIndexOnLine(t.Name, line); //换乘站在换乘线上的索引
    627                                     if (iix == -1) continue;
    628                                     var ix2 = GetIndexOnLine(depStation, t.LineNo); //始发站在换乘站所在线路上的索引
    629                                     var iix2 = GetIndexOnLine(t.Name, t.LineNo); //换乘站在始发站所在线路上的索引
    630 
    631                                     var ixRange = line.Stations.Between(ix, iix).Select(x => x.Name).ToList();
    632                                     var ixRange2 = GetLine(t.LineNo).Stations.Between(ix2, iix2).Select(x => x.Name).ToList();
    633                                     var ixh = ixRange.Count - 1;
    634                                     var ixh2 = ixRange2.Count - 1;
    635                                     var h = ixh + ixh2;
    636                                     if (ix < iix) ixRange.Reverse();
    637                                     if (ix2 > iix2) ixRange2.Reverse();
    638                                     var rs = msg_transOnce.FormatTo(GetLine(t.LineNo).ToString(), depStation, ixh2, t.Name,
    639                                         line.ToString(), ixh, destStation,
    640                                         ixRange2.ToJoinString(),
    641                                         ixRange.Where(x => !x.IsSame(t.Name)).ToJoinString(), h);
    642                                     result.Add(new QueryResult()
    643                                     {
    644                                         Description = rs,
    645                                         Range = h,
    646                                         TransferTimes = 1,
    647                                         TransferStations = new List<string>() { t.Name }
    648                                     });
    649                                 }
    650                             }
    651                         }
    652                         #endregion
    653                     }
    654                 }
    655                 #endregion
    656             }
    657 
    658             //查找其他可能性
    659             #region 深度挖掘其他方案
    660             //找出经过始发站和到达站的线路中共同穿过的公共线路,寻找换乘方案
    661             var connLines = GetCommonLines(depStation, destStation);
    662             if (connLines.Count > 0)
    663             {
    664                 var transDep = new List<Station>();
    665                 var transDest = new List<Station>();
    666                 foreach (var depLine in afterDepLines)
    667                 {
    668                     //在经过始发站的线路中的站点中找到可换乘到公共线路的站点
    669                     var trans = depLine.GetTransStations()
    670                             .Where(x => x.Name != depStation && x.Name != destStation && connLines.Exists(y => x.TransferNo.Contains(y.No)))
    671                             .ToList();
    672                     transDep.AddRange(trans);
    673                 }
    674                 foreach (var destLine in afterDestLines)
    675                 {
    676                     //在经过到达站的线路中的站点中找到可换乘到公共线路的站点
    677                     var trans = destLine.GetTransStations()
    678                             .Where(x => x.Name != depStation && x.Name != destStation && connLines.Exists(y => x.TransferNo.Contains(y.No)))
    679                             .ToList();
    680                     transDest.AddRange(trans);
    681                 }
    682                 foreach (var d1 in transDep)
    683                 {
    684                     foreach (var d2 in transDest)
    685                     {
    686                         //找出交叉站点,即可换乘同一条公共线路的站点
    687                         var inters = d1.TransferNo.Split(',').Intersect(d2.TransferNo.Split(',')).ToList();
    688                         if (!inters.Any() || d1.Name.IsSame(d2.Name)) continue;
    689                         var tranLine = GetLine(inters.First());
    690                         var depLine = GetLine(d1.LineNo);
    691                         var destLine = GetLine(d2.LineNo);
    692                         var ix1 = GetIndexOnLine(depStation, depLine);
    693                         var ix2 = GetIndexOnLine(d1.Name, depLine);
    694                         var iix1 = GetIndexOnLine(d1.Name, tranLine);
    695                         var iix2 = GetIndexOnLine(d2.Name, tranLine);
    696                         var iiix1 = GetIndexOnLine(d2.Name, destLine);
    697                         var iiix2 = GetIndexOnLine(destStation, destLine);
    698 
    699                         var depRange = depLine.Stations.Between(ix1, ix2).Select(x => x.Name).ToList();
    700                         var transRange = tranLine.Stations.Between(iix1, iix2).Select(x => x.Name).ToList();
    701                         var destRange = destLine.Stations.Between(iiix1, iiix2).Select(x => x.Name).ToList();
    702                         var r1 = depRange.Count - 1;
    703                         var r2 = transRange.Count - 1;
    704                         var r3 = destRange.Count - 1;
    705                         var r = r1 + r2 + r3;
    706                         if (ix1 > ix2) depRange.Reverse();
    707                         if (iix1 > iix2) transRange.Reverse();
    708                         if (iiix1 > iiix2) destRange.Reverse();
    709                         string rs;
    710                         if (r1 > 0 && r2 > 0 && r3 > 0)
    711                         {
    712                             rs = msg_transTwice.FormatTo(depLine.ToString(), depStation, r1, d1.Name, tranLine.ToString(), r2,
    713                                     d2.Name, destLine.ToString(), r3, destStation, depRange.ToJoinString(),
    714                                       transRange.Where(x => !x.IsSame(d1.Name)).ToJoinString(),
    715                                     destRange.Where(x => !x.IsSame(d1.Name) && !x.IsSame(d2.Name)).ToJoinString(), r);
    716                             result.Add(new QueryResult()
    717                             {
    718                                 Description = rs,
    719                                 Range = r,
    720                                 TransferTimes = 2,
    721                                 TransferStations = new List<string>() { d1.Name, d2.Name }
    722                             });
    723                         }
    724                         else if (r1 > 0 && r2 == 0 && r3 > 0)
    725                         {
    726                             rs = msg_transOnce.FormatTo(GetLine(inters.First()).ToString(), depStation, r1, d2.Name,
    727                                   destLine.ToString(), r3, destStation,
    728                                   depRange.ToJoinString(),
    729                                  destRange.Where(x => !x.IsSame(d2.Name)).ToJoinString(), r);
    730                             result.Add(new QueryResult()
    731                             {
    732                                 Description = rs,
    733                                 Range = r,
    734                                 TransferTimes = 1,
    735                                 TransferStations = new List<string>() { d2.Name }
    736                             });
    737                         }
    738                         else
    739                         {
    740                             rs = msg_transOnce.FormatTo(depLine.ToString(), depStation, r1, d1.Name, tranLine.ToString(), r2,
    741                                     destStation, depRange.ToJoinString(),
    742                                     transRange.Where(x => !x.IsSame(d1.Name)).ToJoinString(), r);
    743                             result.Add(new QueryResult()
    744                             {
    745                                 Description = rs,
    746                                 Range = r,
    747                                 TransferTimes = 1,
    748                                 TransferStations = new List<string>() { d1.Name }
    749                             });
    750                         }
    751                     }
    752                 }
    753             }
    754             #endregion
    755 
    756             //重新组织数据
    757             result.ForEach(x =>
    758             {
    759                 var desc = x.Description.Split(new string[] { "
    " }, StringSplitOptions.RemoveEmptyEntries);
    760                 x.Suggestion = desc[0];
    761                 x.Route = desc[2];
    762             });
    763             //去除重复方案,保留一个
    764             var gyResult = result.GroupBy(x => x.Route).Select(x => x.First()).ToList();
    765             //移除逗逼方案,例如:A-B-A-C
    766             gyResult.RemoveAll(x => x.Route.Split(new string[] { depStation }, StringSplitOptions.RemoveEmptyEntries).Length > 2
    767             || x.Route.Split(new string[] { destStation }, StringSplitOptions.RemoveEmptyEntries).Length > 2);
    768             return gyResult;
    769         }

    因为只做了北京、上海、深圳、广州四个城市的站点数据,所以演示只能查询这四个城市的地铁换乘,大家可以补充自己想要的城市的地铁数据,格式请参照源码中上面四个城市的xml格式。

    最后附上源码地址,https://gitee.com/herubin/subway_transfer_query_tool

    api接口地址:http://www.xiaoboke.net/api/subway/q?dep=%E6%B5%B7%E7%8F%A0%E5%B9%BF%E5%9C%BA&dest=%E5%A4%A7%E5%89%A7%E9%99%A2&city=guangzhou 

    参数说明:dep为始发站,dest为到达站,city为所在城市拼音,这个是专门为其他程序调用开放的接口

    我在我的小博客也发布了:http://www.xiaoboke.net/admin/blog/article/26

    核心方法代码有点多,并不是有意这样写,正在想法子压缩代码,大家将就看吧(*^__^*) 

    有兴趣的朋友可以看看,欢迎大家提出改进意见,码个代码不容易,各位大哥大姐的点赞是我不断努力的动力​,谢谢!

  • 相关阅读:
    AS3打开本地文件
    Android上的Adobe AIR应用程序运行环境发布了!
    as3 创建遮罩层和自定义带参数的事件
    NetStream.appendBytes, 走向Flash P2P VOD的第一步
    BitmapData的整理
    AS3 in FlashDevelop
    站内站外AS3资源导航帖
    swf不能访问本地资源的解决办法
    JSON 序列化和反序列化——JavaScriptSerializer实现
    Json.net说法——(一)修饰标签,日期序列化
  • 原文地址:https://www.cnblogs.com/myonly/p/subwaytool.html
Copyright © 2011-2022 走看看