【问题标题】:Sorting number of lists according to indexes and priority根据索引和优先级对列表的数量进行排序
【发布时间】:2011-12-23 16:42:09
【问题描述】:

我有一个列表集合,每个列表包含大约 6 到 7 个值。喜欢,

list1 = 2,4,7,4,9,5
list2 = 4,3,7.3,9,8,1.2
list3 = 2,2.4,7,9,8,5
list4 = 9,1.6,4,3,4,1
list5 = 2,5,7,9,1,4
list6 = 6,8,7,2,1,5
list7 = 4,2,5,2,1,3

现在我想用 index1 作为主要,index3 作为次要,index2 作为第三级,依此类推。也就是说,输出应该是这样的:

 2,2.4,7,9,8,5
 2,4,7,4,9,5
 2,5,7,9,1,4
 4,2,5,2,1,3
 6,8,7,2,1,5
 9,1.6,4,3,4,1

我希望首先对 index1 的列表顺序进行排序,如果 index1 的值相同,则在 index3 上进行排序,如果与 index2 上的值相同。这里列表的数量较少,可以增加到 20,索引也可以增加到 20。

我想知道的算法和iTunes歌曲排序的算法是一样的,同一张专辑的歌曲先排序,然后是艺术家,然后是排名,然后是名称。如果专辑名称相同,则对专辑进行排序,如果相同,则对艺术家进行排序,然后按排名等等。代码可以在 C/C++/tcl/shell 中。

【问题讨论】:

  • 真的会是 index3 在 index 2 之前吗?如果是,那么你的解释中的等等不足以解释排序谓词。

标签: c++ c shell sorting tcl


【解决方案1】:

这是一个 C++ 解决方案:

#include <iostream>
#include <vector>
#include <algorithm>

template <typename Array, typename CompareOrderIndex>
struct arrayCompare
{
   private:
      size_t
         size ;
      CompareOrderIndex
        index ;
   public:

      arrayCompare( CompareOrderIndex idx ) :  size( idx.size() ), index(idx)  { }

      bool helper( const Array &a1, const Array &a2, unsigned int num ) const
      {
         if( a1[ index[size-num] ] > a2[ index[size-num] ] )
         {
            return false ;
         }

         if( !(a1[ index[size-num] ] < a2[ index[size-num] ]) )
         {
            if( 1 != num )
            {
               return helper( a1, a2, num-1 ) ;   
            }
         }

         return true ;
      }

      bool operator()(  const Array &a1, const Array &a2 ) const
      {
         return helper( a1, a2, size ) ; 

      }
} ;

int main()
{
   std::vector< std::vector<float> > lists = {     { 2, 4,   7,   4, 9, 5},
                                                   { 4, 3,   7.3, 9, 8, 1.2 },
                                                   { 2, 2.4, 7,   9, 8, 5 },
                                                   { 4, 2,   5,   2, 1, 3 },
                                                   { 9, 1.6, 4,   3, 4, 1 },
                                                   { 2, 5,   7,   9, 1, 4 },
                                                   { 6, 8,   7,   2, 1, 5 },
                                                   { 4, 2,   5,   2, 1, 1 },
                                                };
   //
   // Specify the column indexes to compare and the order to compare.
   // In this case it will first compare column 1 then 3 and finally 2.
   // 
   //std::vector<int> indexOrder = { 0, 2, 1, 3, 4 ,5  } ;
   std::vector<int> indexOrder = { 0, 2, 1  } ;

   arrayCompare< std::vector<float>, std::vector<int>> compV( indexOrder ) ;

   std::sort( lists.begin(), lists.end(), arrayCompare< std::vector<float>, std::vector<int>>( indexOrder )  ) ;

    for(auto p: lists) 
    {
       for( unsigned int i = 0; i < p.size(); ++i )
       {
          unsigned int idx = ( i > (indexOrder.size() -1) ? i : indexOrder[i] ) ;

          std::cout << p[idx] << ", " ;
       }
       std::cout << std::endl ;
    }
}

【讨论】:

    【解决方案2】:

    既然您要求 Tcl 解决方案:

    set lol {
       {2 4 7 4 9 5}
       {4 3 7.3 9 8 1.2}
       {2 2.4 7 9 8 5}
       {9 1.6 4 3 4 1}
       {2 5 7 9 1 4}
       {6 8 7 2 1 5}
       {4 2 5 2 1 3}
    }
    
    set ::EPS 10e-6
    proc compareLists {ixo e1 e2} {
       foreach ix $ixo {
          set d [expr {[lindex $e1 $ix] - [lindex $e2 $ix]}]
          if {abs($d) > $::EPS} {
             return [expr {($d>0)-($d<0)}]
          }
       }
       return 0
    }
    
    foreach li [lsort -command [list compareLists {0 2 1}] $lol] {
       puts $li
    }
    

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      要在 Tcl 中执行此操作,假设没有大量数据(几 MB 不会“巨大”),最简单的方法是:

      # Read the values in from stdin, break into lists of lists
      foreach line [split [read stdin] "\n"] {
          lappend records [split $line ","]
      }
      
      # Sort twice, first by secondary key then by primary (lsort is _stable_)
      set records [lsort -index 1 -real $records]
      set records [lsort -index 0 -real $records]
      
      # Write the values back out to stdout
      foreach record $records {
          puts [join $record ","]
      }
      

      如果您使用比简单数字更复杂的东西,请考虑使用 Tcllib 中的 csv 包进行解析和格式化,因为它将处理 Real Data 中出现的许多句法问题。如果您正在处理大量数据(其中“大量”取决于您部署的内存量),那么请考虑使用更面向流的方法来处理数据(并且在内存处理中还有一些其他优化)并且您可能还想使用lsort-command 选项来提供自定义比较器,以便您只能排序一次;唉,自定义比较器的性能影响非常高,但对于许多记录而言,减少比较次数会胜出。或者将数据推送到 SQLite 或 Postgres 等数据库中。

      【讨论】:

      • 这就是我最初所做的,但我不需要制作新文件并且存储在数据结构中并不容易。感谢您的输入。 :)
      • @user954134:您真正寻找的内容越详细,您就越有可能获得直接有用的东西。特别是,说明所需的数据源和接收器以及要处理多少数据,这些都会有很大帮助。 (排序 1MB 和 1TB 有很大区别!)
      【解决方案4】:
      sort -n -t ',' -k 1 -k 3 -k 2
      

      将列表作为单独的行输入。

      【讨论】:

      • 这会将数字处理为字符串还是整数?
      • @Rup: 作为浮动,由于-n
      • 在 tcl 方面有没有可能的解决方案。 :)
      【解决方案5】:

      你可以使用STL's sort,然后你所要做的就是写一个比较函数来做你想要的(链接中的例子应该足够好了)。

      【讨论】:

        猜你喜欢
        • 2014-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-08
        • 2015-01-08
        相关资源
        最近更新 更多