愿有人陪你颠沛流离,如果没有,愿你成为自己的太阳。
日常生活中,上班下班坐地铁已经是常事,每当我想去某一个远一点的地方,如果有地铁首选就是地铁,因为方便嘛!每次坐地铁,我们都是凭肉眼去得出我们心中最佳的换乘方案,但是,如果对于线路较少的城市来说,这个方法是最快的,但是如果对于线路较多的城市,例如北京或者上海,十几条线路交叉穿梭,我们可能看到都晕了,怎么坐才是时间最短路程最短的,我们要算出来不是不可以但是很麻烦,于是,闲着没事,我就想写一个通用的地铁换乘查询程序,想用计算机运算得出科学一点的换乘方案供自己参考,假设先不考虑站点间的距离差异,我们以乘坐站点数最少为最优方案,依照这个条件去编码实现查找的算法,其实也没用上什么高大上的算法,因为也不会哈哈,话不多说,先上效果图:
有对应城市的线路图:
站点智能提示:
项目结构图:
我的开发思路:
1、采用xml存储站点数据,如下:
2、代码中使用集合初始化线路数据
/// <summary> /// 初始化地铁线路数据 /// </summary> /// <param name="city">城市</param> public static void InitSubwayLine(CityEnum city) { if (AllSubwayLines != null && AllSubwayLines.Any() && _currentCity == city) return; _currentCity = city; var xmlName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xml/" + city.ToString() + ".xml"); _doc = XDocument.Load(xmlName); AllSubwayLines = _doc.Root.Elements().Select(x => { var line = new SubwayLine { No = x.Attribute("No").Value, Name = x.Attribute("Name").Value, IsRound = x.Attribute("IsRound") == null ? false : bool.Parse(x.Attribute("IsRound").Value), Stations = x.Elements().Select((y, i) => new Station { Index = i, Name = y.Attribute("Name").Value, LineNo = x.Attribute("No").Value, CanTransfer = y.Attribute("CanTransfer") == null ? false : bool.Parse(y.Attribute("CanTransfer").Value), TransferNo = y.Attribute("TransferNo") == null ? null : y.Attribute("TransferNo").Value }).ToList() }; var translines = line.GetTransStations().Select(z => z.TransferNo.Split(',')).ToList(); foreach (var transline in translines) { foreach (var li in transline) { line.TransferLines.Add(li); } } line.TransferLines = line.TransferLines.Distinct().ToList(); return line; }).ToList(); }
3、分多种情况进行处理,主要代码:
/// <summary> /// 获取地铁乘车信息 /// </summary> /// <param name="depStation">出发站</param> /// <param name="destStation">到达站</param> /// <param name="city">所在城市</param> /// <returns>返回各种换乘方案</returns> public static List<QueryResult> GetRideSubwayInfo(string depStation, string destStation, CityEnum city) { InitSubwayLine(city); if (string.IsNullOrWhiteSpace(depStation) || string.IsNullOrWhiteSpace(destStation) || !AllSubwayLines.Exists(x => x.Stations.Exists(y => y.Name.Equals(depStation))) || !AllSubwayLines.Exists(x => x.Stations.Exists(y => y.Name.Equals(destStation)))) return null;//出发站或到达站在线路上不存在! //各种换乘提示 //同一条线路 var msg_oneline = "在{0}【{1}】上车,经过{2}站到达目的站【{3}】。\r\n具体线路为:\r\n(出发){4}(到达)\r\n总搭乘站点数:{5}\r\n"; //换乘1次 var msg_transOnce = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站到达目的站【{6}】。\r\n具体线路为:\r\n(出发){7}(此处换乘{4})-->{8}(到达)\r\n总搭乘站点数:{9}\r\n"; //换乘2次 var msg_transTwice = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站到达目的站【{9}】。\r\n具体线路为:\r\n(出发){10}(此处换乘{4})-->{11}(此处换乘{7})-->{12}(到达)\r\n总搭乘站点数:{13}\r\n"; //换乘3次 var msg_transThreetimes = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站在【{9}】下车,换乘{10},经过{11}站到达目的站【{12}】。" + "\r\n具体线路为:\r\n(出发){13}(此处换乘{4})-->{14}(此处换乘{7})-->{15}(此处换乘{10})-->{16}(到达)\r\n总搭乘站点数:{17}\r\n"; //换乘4次 var msg_transFourtimes = "在{0}【{1}】上车,经过{2}站在【{3}】下车,换乘{4},经过{5}站在【{6}】下车,换乘{7},经过{8}站在【{9}】下车,换乘{10},经过{11}站在【{12}】下车,换乘{13},经过{14}站到达目的站【{15}】。" + "\r\n具体线路为:\r\n(出发){16}(此处换乘{4})-->{17}(此处换乘{7})-->{18}(此处换乘{10})-->{19}(此处换乘{13})-->{20}(到达)\r\n总搭乘站点数:{21}\r\n"; //保存各种换乘方案 var result = new List<QueryResult>(); //第一步:先查找始发站和到达站在哪一条线路 var afterDepLines = GetAcrossLines(depStation); var afterDestLines = GetAcrossLines(destStation); //根据同一条线和不同线路展开分析 if (IsSameLine(depStation, destStation)) { #region 同一条线路 var commLines = afterDepLines.Where(x => afterDestLines.Select(y => y.No).Contains(x.No)).ToList(); //判断线路是否相同,相同直接计算站点距离 var depIndex = GetIndexOnLine(depStation, commLines.First()); var destIndex = GetIndexOnLine(destStation, commLines.First()); var crossStations = commLines.First().Stations.Between(depIndex, destIndex).Select(x => x.Name).ToList(); var range = crossStations.Count - 1; if (depIndex > destIndex) crossStations.Reverse(); var rs = msg_oneline.FormatTo(commLines.First().ToString(), depStation, range, destStation, crossStations.ToJoinString(), range); result.Add(new QueryResult() { Description = rs, Range = range }); #endregion } else { #region 不同线路 if (!IsTransferStation(depStation) && !IsTransferStation(destStation))//如果始发站和终点站都不是换乘站,则表示始发站和到达站都是只有一条线路通过 { if (afterDepLines.First().IsIntersect(afterDestLines.First())) { #region 如果两条线路交叉,一定有换乘站点 var clist = GetAcrossStations(afterDepLines.First(), afterDestLines.First()).Select(x => x.Name).ToList(); var i = GetIndexOnLine(depStation, afterDepLines.First()); var j = GetIndexOnLine(clist.First(), afterDepLines.First()); var k = GetIndexOnLine(destStation, afterDestLines.First()); var l = GetIndexOnLine(clist.First(), afterDestLines.First()); var coss1 = afterDepLines.First().Stations.Between(i, j).Select(x => x.Name).ToList(); var coss2 = afterDestLines.First().Stations.Between(k, l).Select(x => x.Name).ToList(); if (i > j) coss1.Reverse(); if (k < l) coss2.Reverse(); var rang1 = coss1.Count - 1; var rang2 = coss2.Count - 1; var h = rang1 + rang2; //站点数 var rs = msg_transOnce.FormatTo(afterDepLines.First().ToString(), depStation, rang1, clist.First(), afterDestLines.First().ToString(), rang2, destStation, coss1.ToJoinString(), coss2.Where(x => x != clist.First()).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferStations = new List<string>() { clist.First() }, TransferTimes = 1 }); #endregion } else { #region 不交叉,需要通过第三条线路换乘,即多次换乘 var depSta = GetStation(depStation); var destSta = GetStation(destStation); //找出两条线路的可换乘站点,找出可换乘相同线路的站点 var trans1 = afterDepLines.First().GetTransStations(); var trans2 = afterDestLines.First().GetTransStations(); var trans3 = new List<Station>(); var trans4 = new List<Station>(); var expets = trans1.Join(trans2, x => x.TransferNo, y => y.TransferNo, (x, y) => { trans3.Add(x); trans4.Add(y); return x.Name + "---" + y.Name; }).ToList(); if (expets.Any()) { #region 两次换乘 //trans3.Count和trans4.Count必定相等 //计算最短距离,列出所有换乘方案 for (var i = 0; i < trans3.Count; i++) { var tranLine = GetLine(trans3[i].TransferNo); //获取这两个站点在此线路的索引 var ix1 = depSta.Index; var ix2 = destSta.Index; var iix1 = GetIndexOnLine(trans3[i].Name, depSta.LineNo); var iix2 = GetIndexOnLine(trans4[i].Name, destSta.LineNo); var tx1 = GetIndexOnLine(trans3[i].Name, tranLine); var tx2 = GetIndexOnLine(trans4[i].Name, tranLine); var depRange = afterDepLines.First().Stations.Between(ix1, iix1).Select(x => x.Name).ToList(); var destRange = afterDestLines.First().Stations.Between(ix2, iix2).Select(x => x.Name).ToList(); var transRange = tranLine.Stations.Between(tx1, tx2).Select(x => x.Name).ToList(); if (ix1 > iix1) depRange.Reverse(); if (ix2 < iix2) destRange.Reverse(); if (tx1 > tx2) transRange.Reverse(); var r1 = depRange.Count - 1; var r2 = destRange.Count - 1; var r3 = transRange.Count - 1; var r = r1 + r2 + r3; var rs = msg_transTwice.FormatTo(afterDepLines.First().ToString(), depStation, r1, trans3[i].Name, tranLine.ToString(), r3, trans4[i].Name, afterDestLines.First().ToString(), r2, destStation, depRange.ToJoinString(), transRange.Where(x => !x.IsSame(trans3[i].Name) && !x.IsSame(trans4[i].Name)).ToJoinString(), destRange.ToJoinString(), r); result.Add(new QueryResult() { Description = rs, Range = r, TransferTimes = 2, TransferStations = new List<string>() { trans3[i].Name, trans4[i].Name } }); } #endregion } #region 查找3次以上换乘的可能结果,寻求最短距离 var trlines1 = afterDepLines.First().TransferLines.Select(GetLine).ToList(); var trlines2 = afterDestLines.First().TransferLines.Select(GetLine).ToList(); var destss = new List<Station>(); #region 换乘3次 foreach (var depline in trlines1) { foreach (var destline in trlines2) { var ss = destline.GetAcrossStations(depline); if (!ss.Any()) continue; //3次换乘 var slist1 = afterDepLines.First().GetAcrossStations(depline); if (!slist1.Any()) continue; var s1 = slist1.GetClosestStation(depSta.Name); var s1_ix1 = depSta.Index; var s1_ix2 = s1.Index; var s1_range = afterDepLines.First() .Stations.Between(s1_ix1, s1_ix2) .Select(x => x.Name) .ToList(); var s1_h = s1_range.Count - 1; if (s1_ix1 > s1_ix2) s1_range.Reverse(); var s2_ix1 = GetIndexOnLine(s1.Name, depline); var s2_ix2 = GetIndexOnLine(ss.First().Name, depline); var s2_range = depline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList(); var s2_h = s2_range.Count - 1; if (s2_ix1 > s2_ix2) s2_range.Reverse(); var slist3 = destline.GetAcrossStations(afterDestLines.First()); if (!slist3.Any()) continue; var s3 = slist3.GetClosestStation(ss.First().Name); var s3_ix1 = s3.Index; var s3_ix2 = ss.First().Index; var s3_range = destline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList(); var s3_h = s3_range.Count - 1; if (s3_ix1 < s3_ix2) s3_range.Reverse(); var s4_ix1 = GetIndexOnLine(s3.Name, afterDestLines.First()); var s4_ix2 = destSta.Index; var s4_range = afterDestLines.First() .Stations.Between(s4_ix1, s4_ix2) .Select(x => x.Name) .ToList(); var s4_h = s4_range.Count - 1; if (s4_ix1 > s4_ix2) s4_range.Reverse(); var h = s1_h + s2_h + s3_h + s4_h; var rs = msg_transThreetimes.FormatTo(afterDepLines.First().ToString(), depStation, s1_h, s1.Name, depline.ToString(), s2_h, ss.First().Name, GetLine(ss.First().LineNo).ToString(), s3_h, s3.Name, afterDestLines.First().ToString(), s4_h, destStation, s1_range.ToJoinString(), s2_range.Where(x => x != s1.Name).ToJoinString(), s3_range.Where(x => x != ss.First().Name).ToJoinString(), s4_range.Where(x => x != s3.Name).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 3, TransferStations = new List<string>() { s1.Name, ss.First().Name, s3.Name } }); destss.AddRange(ss); } } #endregion if (!destss.Any()) //换乘4次 { #region 换乘4次 foreach (var depline in trlines1) { foreach (var destline in trlines2) { var deptrlines = depline.TransferLines.Where(x => x != afterDepLines.First().No) .Select(GetLine) .ToList(); foreach (var line in deptrlines) { var s1 = line.GetAcrossStations(destline); if (!s1.Any()) continue; //4次换乘 var trlist1 = afterDepLines.First().GetAcrossStations(depline); if (!trlist1.Any()) continue; var tr1 = trlist1.GetClosestStation(depSta.Name); var s1_ix1 = depSta.Index; var s1_ix2 = tr1.Index; var s1_range = afterDepLines.First() .Stations.Between(s1_ix1, s1_ix2) .Select(x => x.Name) .ToList(); var h1 = s1_range.Count - 1; if (s1_ix1 > s1_ix2) s1_range.Reverse(); var trlist2 = GetLine(tr1.TransferNo).GetAcrossStations(line); if (!trlist2.Any()) continue; var tr2 = trlist2.GetClosestStation(tr1.Name); var s2_ix1 = GetIndexOnLine(tr1.Name, depline); var s2_ix2 = tr2.Index; var s2_range = depline.Stations.Between(s2_ix1, s2_ix2) .Select(x => x.Name) .ToList(); var h2 = s2_range.Count - 1; if (s2_ix1 > s2_ix2) s2_range.Reverse(); var s3_ix1 = GetIndexOnLine(tr2.Name, line); var s3_ix2 = s1.First().Index; var s3_range = line.Stations.Between(s3_ix1, s3_ix2) .Select(x => x.Name) .ToList(); var h3 = s3_range.Count - 1; if (s3_ix1 > s3_ix2) s3_range.Reverse(); var trlist3 = destline.GetAcrossStations(afterDestLines.First()); if (!trlist3.Any()) continue; var tr3 = trlist3.GetClosestStation(s1.First().Name); var s4_ix1 = GetIndexOnLine(s1.First().Name, destline); var s4_ix2 = tr3.Index; var s4_range = destline.Stations.Between(s4_ix1, s4_ix2) .Select(x => x.Name) .ToList(); var h4 = s4_range.Count - 1; if (s4_ix1 > s4_ix2) s4_range.Reverse(); var s5_ix1 = GetIndexOnLine(tr3.Name, afterDestLines.First()); var s5_ix2 = destSta.Index; var s5_range = afterDestLines.First() .Stations.Between(s5_ix1, s5_ix2) .Select(x => x.Name) .ToList(); var h5 = s5_range.Count - 1; if (s5_ix1 > s5_ix2) s5_range.Reverse(); var h = h1 + h2 + h3 + h4 + h5; var rs = msg_transFourtimes.FormatTo(afterDepLines.First().ToString(), depStation, h1, tr1.Name, depline.ToString(), h2, tr2.Name, line.ToString(), h3, s1.First().Name, destline.ToString(), h4, tr3.Name, afterDestLines.First().ToString(), h5, destStation, s1_range.ToJoinString(), s2_range.Where(x => x != tr1.Name).ToJoinString(), s3_range.Where(x => x != tr2.Name).ToJoinString(), s4_range.Where(x => x != tr2.Name && x != s1.First().Name).ToJoinString(), s5_range.Where(x => x != tr3.Name).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 4, TransferStations = new List<string>() { tr1.Name, tr2.Name, s1.First().Name, tr3.Name } }); destss.AddRange(s1); } } } #endregion } if (!destss.Any())//换乘4次以上 { } #endregion #endregion } } else //始发站和到达站有其中一个是换乘站 { //找出到达站经过的路线和始发站所在路线的交叉线路 var crossLines = GetAcrossLines(depStation, destStation); //分三种情况:1、始发站不是换乘站而到达站是换乘站;2、始发站是换乘站而到达站不是换乘站;3、始发站和到达站都是换乘站,根据情况展开分析 if (!IsTransferStation(depStation) && IsTransferStation(destStation)) { #region 情况1:始发站不是换乘站而到达站是换乘站 if (crossLines.Count > 0) //依赖交叉线 { var listTrans = new List<Station>(); foreach (var line in crossLines) { //找出每条交叉线换乘到始发站线路的所有换乘站 var ss = line.GetTransStations() .Where(x => x.TransferNo.IsSame(afterDepLines.First().No)) .ToList(); listTrans.AddRange(ss); } var depIx = GetIndexOnLine(depStation, afterDepLines.First()); var tranStas = listTrans.Select( s => new { sta = s, ix = GetIndexOnLine(s.Name, afterDepLines.First()) }) .ToList(); foreach (var sta in tranStas) { var destIx = GetIndexOnLine(destStation, sta.sta.LineNo); var tranIx = GetIndexOnLine(sta.sta.Name, sta.sta.LineNo); var coss1 = afterDepLines.First() .Stations.Between(depIx, sta.ix) .Select(x => x.Name) .ToList(); var coss2 = GetLine(sta.sta.LineNo) .Stations.Between(destIx, tranIx) .Select(x => x.Name) .ToList(); var rang1 = coss1.Count - 1; var rang2 = coss2.Count - 1; var h = rang1 + rang2; //站点数 if (depIx > sta.ix) coss1.Reverse(); if (destIx < tranIx) coss2.Reverse(); var rs = msg_transOnce.FormatTo(afterDepLines.First().ToString(), depStation, rang1, sta.sta.Name, GetLine(sta.sta.LineNo).ToString(), rang2, destStation, coss1.ToJoinString(), coss2.Where(x => x != sta.sta.Name).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 1, TransferStations = new List<string>() { sta.sta.Name } }); } } //查找其他换乘可能 var depSta = GetStation(depStation); var trlinesDep = afterDepLines.First().TransferLines.Select(GetLine).ToList(); foreach (var depline in afterDestLines) { var trlineItems = depline.TransferLines.Select(GetLine).ToList(); foreach (var iline in trlineItems) { foreach (var destline in trlinesDep) { var ss = destline.GetAcrossStations(iline); if (!ss.Any()) continue; //3次换乘 var slist1 = afterDepLines.First().GetAcrossStations(destline); if (!slist1.Any()) continue; var s1 = slist1.GetClosestStation(depStation); var s1_ix1 = depSta.Index; var s1_ix2 = s1.Index; var s1_range = afterDepLines.First() .Stations.Between(s1_ix1, s1_ix2) .Select(x => x.Name) .ToList(); var s1_h = s1_range.Count - 1; if (s1_ix1 > s1_ix2) s1_range.Reverse(); var s2 = ss.GetClosestStation(s1.Name); var s2_ix1 = GetIndexOnLine(s1.Name, destline); var s2_ix2 = GetIndexOnLine(s2.Name, destline); var s2_range = destline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList(); var s2_h = s2_range.Count - 1; if (s2_ix1 > s2_ix2) s2_range.Reverse(); var slist3 = iline.GetAcrossStations(depline); if (!slist3.Any()) continue; var s3 = slist3.GetClosestStation(s2.Name); var s3_ix1 = s3.Index; var s3_ix2 = GetIndexOnLine(s2.Name, iline); var s3_range = iline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList(); var s3_h = s3_range.Count - 1; if (s3_ix1 < s3_ix2) s3_range.Reverse(); var s4_ix1 = GetIndexOnLine(s3.Name, depline); var s4_ix2 = GetIndexOnLine(destStation, depline); var s4_range = depline.Stations.Between(s4_ix1, s4_ix2) .Select(x => x.Name) .ToList(); var s4_h = s4_range.Count - 1; if (s4_ix1 > s4_ix2) s4_range.Reverse(); var h = s1_h + s2_h + s3_h + s4_h; if (s2_h == 0 || s3_h == 0 || s4_h == 0 || destline.No.IsSame(iline.No)) continue; var rs = msg_transThreetimes.FormatTo(afterDepLines.First().ToString(), depStation, s1_h, s1.Name, destline.ToString(), s2_h, s2.Name, iline.ToString(), s3_h, s3.Name, depline.ToString(), s4_h, destStation, s1_range.ToJoinString(), s2_range.Where(x => x != s1.Name).ToJoinString(), s3_range.Where(x => x != s2.Name).ToJoinString(), s4_range.Where(x => x != s3.Name).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 3, TransferStations = new List<string>() { s1.Name, s2.Name, s3.Name } }); } } } #endregion } if (IsTransferStation(depStation) && !IsTransferStation(destStation)) { #region 情况2:始发站是换乘站而到达站不是换乘站 var transLines = afterDepLines.Where( x => x.Stations.Exists( y => y.CanTransfer && y.TransferNo.Contains(afterDestLines.First().No))) .ToList(); if (transLines.Any()) { var clist = GetAcrossStations(transLines.First(), afterDestLines.First()) .Select(x => x.Name) .ToList(); var i = GetIndexOnLine(depStation, transLines.First()); var j = GetIndexOnLine(clist.First(), transLines.First()); var k = GetIndexOnLine(destStation, afterDestLines.First()); var l = GetIndexOnLine(clist.First(), afterDestLines.First()); var coss1 = transLines.First().Stations.Between(i, j).Select(x => x.Name).ToList(); var coss2 = afterDestLines.First().Stations.Between(k, l).Select(x => x.Name).ToList(); var rang1 = coss1.Count - 1; var rang2 = coss2.Count - 1; var h = rang1 + rang2; //站点数 if (i > j) coss1.Reverse(); if (k < l) coss2.Reverse(); var rs = msg_transOnce.FormatTo(transLines.First().ToString(), depStation, rang1, clist.First(), afterDestLines.First().ToString(), rang2, destStation, coss1.ToJoinString(), coss2.Where(x => x != clist.First()).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 1, TransferStations = new List<string>() { clist.First() } }); } //寻找其他换乘可能 var destSta = GetStation(destStation); var trlinesDest = afterDestLines.First().TransferLines.Select(GetLine).ToList(); foreach (var depline in afterDepLines) { var trlineItems = depline.TransferLines.Select(GetLine).ToList(); foreach (var iline in trlineItems) { foreach (var destline in trlinesDest) { var ss = iline.GetAcrossStations(destline); if (!ss.Any()) continue; //3次换乘 var slist1 = depline.GetAcrossStations(iline); if (!slist1.Any()) continue; var s1 = slist1.GetClosestStation(depStation); var s1_ix1 = GetIndexOnLine(depStation, depline); var s1_ix2 = s1.Index; var s1_range = depline.Stations.Between(s1_ix1, s1_ix2) .Select(x => x.Name) .ToList(); var s1_h = s1_range.Count - 1; if (s1_ix1 > s1_ix2) s1_range.Reverse(); var s2 = ss.GetClosestStation(s1.Name); var s2_ix1 = GetIndexOnLine(s1.Name, iline); var s2_ix2 = GetIndexOnLine(s2.Name, iline); var s2_range = iline.Stations.Between(s2_ix1, s2_ix2).Select(x => x.Name).ToList(); var s2_h = s2_range.Count - 1; if (s2_ix1 > s2_ix2) s2_range.Reverse(); var slist3 = destline.GetAcrossStations(afterDestLines.First()); if (!slist3.Any()) continue; var s3 = slist3.GetClosestStation(ss.First().Name); var s3_ix1 = s3.Index; var s3_ix2 = GetIndexOnLine(s2.Name, destline); var s3_range = destline.Stations.Between(s3_ix1, s3_ix2).Select(x => x.Name).ToList(); var s3_h = s3_range.Count - 1; if (s3_ix1 < s3_ix2) s3_range.Reverse(); var s4_ix1 = GetIndexOnLine(s3.Name, afterDestLines.First()); var s4_ix2 = destSta.Index; var s4_range = afterDestLines.First() .Stations.Between(s4_ix1, s4_ix2) .Select(x => x.Name) .ToList(); var s4_h = s4_range.Count - 1; if (s4_ix1 > s4_ix2) s4_range.Reverse(); var h = s1_h + s2_h + s3_h + s4_h; if (s1_h == 0 || s2_h == 0 || s3_h == 0 || iline.No.IsSame(destline.No)) continue; var rs = msg_transThreetimes.FormatTo(depline.ToString(), depStation, s1_h, s1.Name, iline.ToString(), s2_h, s2.Name, destline.ToString(), s3_h, s3.Name, afterDestLines.First().ToString(), s4_h, destStation, s1_range.ToJoinString(), s2_range.Where(x => x != s1.Name).ToJoinString(), s3_range.Where(x => x != s2.Name).ToJoinString(), s4_range.Where(x => x != s3.Name).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 3, TransferStations = new List<string>() { s1.Name, s2.Name, s3.Name } }); } } } #endregion } if (IsTransferStation(depStation) && IsTransferStation(destStation)) { #region 情况3:始发站和到达站都是换乘站 if (crossLines.Count > 0) //依赖交叉线 { var transStations = GetClosestStation(depStation, true); if ( !transStations.Exists( x => crossLines.Exists(y => y.Stations.Exists(z => x.TransferNo.Split(',').Intersect(z.LineNo.Split(',')).Any())))) { transStations = new List<Station>(); afterDepLines.ForEach(x => { var ctrans = x.GetTransStations(); var ctrans2 = ctrans.Where( y => crossLines.Exists( z => z.Stations.Exists(zz => y.TransferNo.Split(',').Intersect(zz.LineNo.Split(',')).Any()))) .ToList(); transStations.AddRange(ctrans2); }); } var transLine = afterDestLines.Where( x => x.Stations.Exists(y => transStations.Exists(z => z.Name.IsSame(y.Name)))) .ToList(); var intersStas = transStations.Where( x => transLine.Exists( y => y.Stations.Exists( z => z.Name.IsSame(x.Name) && x.TransferNo.Split(',').Intersect(z.LineNo.Split(',')).Any()))) .ToList(); foreach (var line in transLine) { //分别获取换乘站在换乘线上的索引 foreach (var t in intersStas) { var ix = GetIndexOnLine(destStation, line); //目的站在换乘线上的索引 var iix = GetIndexOnLine(t.Name, line); //换乘站在换乘线上的索引 if (iix == -1) continue; var ix2 = GetIndexOnLine(depStation, t.LineNo); //始发站在换乘站所在线路上的索引 var iix2 = GetIndexOnLine(t.Name, t.LineNo); //换乘站在始发站所在线路上的索引 var ixRange = line.Stations.Between(ix, iix).Select(x => x.Name).ToList(); var ixRange2 = GetLine(t.LineNo).Stations.Between(ix2, iix2).Select(x => x.Name).ToList(); var ixh = ixRange.Count - 1; var ixh2 = ixRange2.Count - 1; var h = ixh + ixh2; if (ix < iix) ixRange.Reverse(); if (ix2 > iix2) ixRange2.Reverse(); var rs = msg_transOnce.FormatTo(GetLine(t.LineNo).ToString(), depStation, ixh2, t.Name, line.ToString(), ixh, destStation, ixRange2.ToJoinString(), ixRange.Where(x => !x.IsSame(t.Name)).ToJoinString(), h); result.Add(new QueryResult() { Description = rs, Range = h, TransferTimes = 1, TransferStations = new List<string>() { t.Name } }); } } } #endregion } } #endregion } //查找其他可能性 #region 深度挖掘其他方案 //找出经过始发站和到达站的线路中共同穿过的公共线路,寻找换乘方案 var connLines = GetCommonLines(depStation, destStation); if (connLines.Count > 0) { var transDep = new List<Station>(); var transDest = new List<Station>(); foreach (var depLine in afterDepLines) { //在经过始发站的线路中的站点中找到可换乘到公共线路的站点 var trans = depLine.GetTransStations() .Where(x => x.Name != depStation && x.Name != destStation && connLines.Exists(y => x.TransferNo.Contains(y.No))) .ToList(); transDep.AddRange(trans); } foreach (var destLine in afterDestLines) { //在经过到达站的线路中的站点中找到可换乘到公共线路的站点 var trans = destLine.GetTransStations() .Where(x => x.Name != depStation && x.Name != destStation && connLines.Exists(y => x.TransferNo.Contains(y.No))) .ToList(); transDest.AddRange(trans); } foreach (var d1 in transDep) { foreach (var d2 in transDest) { //找出交叉站点,即可换乘同一条公共线路的站点 var inters = d1.TransferNo.Split(',').Intersect(d2.TransferNo.Split(',')).ToList(); if (!inters.Any() || d1.Name.IsSame(d2.Name)) continue; var tranLine = GetLine(inters.First()); var depLine = GetLine(d1.LineNo); var destLine = GetLine(d2.LineNo); var ix1 = GetIndexOnLine(depStation, depLine); var ix2 = GetIndexOnLine(d1.Name, depLine); var iix1 = GetIndexOnLine(d1.Name, tranLine); var iix2 = GetIndexOnLine(d2.Name, tranLine); var iiix1 = GetIndexOnLine(d2.Name, destLine); var iiix2 = GetIndexOnLine(destStation, destLine); var depRange = depLine.Stations.Between(ix1, ix2).Select(x => x.Name).ToList(); var transRange = tranLine.Stations.Between(iix1, iix2).Select(x => x.Name).ToList(); var destRange = destLine.Stations.Between(iiix1, iiix2).Select(x => x.Name).ToList(); var r1 = depRange.Count - 1; var r2 = transRange.Count - 1; var r3 = destRange.Count - 1; var r = r1 + r2 + r3; if (ix1 > ix2) depRange.Reverse(); if (iix1 > iix2) transRange.Reverse(); if (iiix1 > iiix2) destRange.Reverse(); string rs; if (r1 > 0 && r2 > 0 && r3 > 0) { rs = msg_transTwice.FormatTo(depLine.ToString(), depStation, r1, d1.Name, tranLine.ToString(), r2, d2.Name, destLine.ToString(), r3, destStation, depRange.ToJoinString(), transRange.Where(x => !x.IsSame(d1.Name)).ToJoinString(), destRange.Where(x => !x.IsSame(d1.Name) && !x.IsSame(d2.Name)).ToJoinString(), r); result.Add(new QueryResult() { Description = rs, Range = r, TransferTimes = 2, TransferStations = new List<string>() { d1.Name, d2.Name } }); } else if (r1 > 0 && r2 == 0 && r3 > 0) { rs = msg_transOnce.FormatTo(GetLine(inters.First()).ToString(), depStation, r1, d2.Name, destLine.ToString(), r3, destStation, depRange.ToJoinString(), destRange.Where(x => !x.IsSame(d2.Name)).ToJoinString(), r); result.Add(new QueryResult() { Description = rs, Range = r, TransferTimes = 1, TransferStations = new List<string>() { d2.Name } }); } else { rs = msg_transOnce.FormatTo(depLine.ToString(), depStation, r1, d1.Name, tranLine.ToString(), r2, destStation, depRange.ToJoinString(), transRange.Where(x => !x.IsSame(d1.Name)).ToJoinString(), r); result.Add(new QueryResult() { Description = rs, Range = r, TransferTimes = 1, TransferStations = new List<string>() { d1.Name } }); } } } } #endregion //重新组织数据 result.ForEach(x => { var desc = x.Description.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); x.Suggestion = desc[0]; x.Route = desc[2]; }); //去除重复方案,保留一个 var gyResult = result.GroupBy(x => x.Route).Select(x => x.First()).ToList(); //移除逗逼方案,例如:A-B-A-C gyResult.RemoveAll(x => x.Route.Split(new string[] { depStation }, StringSplitOptions.RemoveEmptyEntries).Length > 2 || x.Route.Split(new string[] { destStation }, StringSplitOptions.RemoveEmptyEntries).Length > 2); return gyResult; }
因为只做了北京、上海、深圳、广州四个城市的站点数据,所以演示只能查询这四个城市的地铁换乘,大家可以补充自己想要的城市的地铁数据,格式请参照上面四个城市的xml格式。
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=guangzhoudep dep为始发站,dest为到达站,city为所在城市拼音
最后附上源码地址,https://gitee.com/herubin/subway_transfer_query_tool
有兴趣的朋友可以看看,欢迎大家提出改进意见
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
楼主 你的Git提交账号密码是啥 修改了窗体的样式想推送!
博主,你的博客用什么开发的啊?有源码么?
@mhq:你好,在首页的关于界面有源码地址:http://www.xiaoboke.net/system/about