我的问题是:
Sql Server数据库表
AdId AdName AdUrl Credits
1 Ad1 abc.com 10
2 Ad2 def.com 40
3 Ad3 fgi.com 30
4 Ad4 xyz.com 10
上面的ads表可能包含1000条记录。我想一次展示10个广告(通过重视具有较高价值的信用)。
我的方法
LINQ
var result = (from u in idb.ads
select u).OrderBy(x => Guid.NewGuid()).Take(10);
但这不会考虑较高的学分。
这是正确的方法吗?如何显示随机广告(已计入功劳),并且相同的广告不会重复显示?
答案 0 :(得分:0)
尝试以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication100
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("AdId", typeof(int));
dt.Columns.Add("AdName", typeof(string));
dt.Columns.Add("AdUrl", typeof(string));
dt.Columns.Add("Credits", typeof (int));
dt.Rows.Add(new object[] {1, "Ad1", "abc.com", 10});
dt.Rows.Add(new object[] {2, "Ad2", "def.com", 40});
dt.Rows.Add(new object[] {3, "Ad3", "fgi.com", 30});
dt.Rows.Add(new object[] {4, "Ad4", "xyz.com", 40});
Random rand = new Random();
List<DataRow> randomRows = dt.AsEnumerable().Select(x => new { row = x, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.row).ToList();
DataTable dt2 = randomRows.CopyToDataTable();
}
}
}
答案 1 :(得分:0)
如何显示随机广告(已考虑功劳),以及 同一广告不会重复显示?
如果要优先考虑学分,可以尝试编写如下查询(可能需要将其转换为LINQ)。
在这里获得更多信用的记录将获得更高的优先级。像credit > 80
将获得最高优先级,而credit < 40
将获得最低优先级。
SELECT TOP 10 *
FROM (SELECT *
FROM (SELECT TOP 80 *
FROM [table]
WHERE credit > 80
ORDER BY Newid())A
UNION ALL
SELECT *
FROM (SELECT TOP 60 *
FROM [table]
WHERE credit <= 80
AND credit > 60
ORDER BY Newid())B
UNION ALL
SELECT *
FROM (SELECT TOP 40 *
FROM [table]
WHERE credit <= 60
AND credit > 40
ORDER BY Newid())C
UNION ALL
SELECT *
FROM (SELECT TOP 20 *
FROM [table]
WHERE credit <= 40
ORDER BY Newid())D) T
ORDER BY Newid()
答案 2 :(得分:0)
您写道:
重视具有较高价值的信用额
这是否意味着,只要您有未展示的功劳为40的广告,就根本不希望展示得分为10的广告?或者,您是说要给信用较高的广告带来更大的展示机会。如果是这样的话:如果学分增加4倍,显示的机会应该增加4倍吗?
假设您不希望显示信用较低的广告,只要您未显示信用较高的广告即可。
step=1
"123456789"[-4:-7:1] yields ""
"123456789"[-4:-6:1] yields ""
"123456789"[-4:-5:1] yields ""
"123456789"[-4:-4:1] yields ""
"123456789"[-4:-3:1] yields "6"
"123456789"[-4:-2:1] yields "67"
"123456789"[-4:-1:1] yields "678"
"123456789"[-4:None:1] yields "6789"
step=-1
"123456789"[-4:-7:-1] yields "654"
"123456789"[-4:-6:-1] yields "65"
"123456789"[-4:-5:-1] yields "6"
"123456789"[-4:-4:-1] yields ""
"123456789"[-4:-3:-1] yields ""
"123456789"[-4:-2:-1] yields ""
"123456789"[-4:-1:-1] yields ""
"123456789"[-4:999999:-1] yields ""
但是,如果您想给所有广告展示的机会,只有信用较高的广告才有机会展示,您应该考虑更高的机会。
最简单的方法是将功劳转换为整数范围,以指示应选择广告的时间:
int nrOfAdsToSelect = ...;
var selectedAds = dbContext.Adds
.Where(ad => !ad.IsSelected)
.OrderyDescending(ad => ad.Credit)
.Take(nrOfAddsToSelect);
采用[00,16]范围内的随机数。选择ID 04的机会比选择ID 01的机会高10倍。
因此,您需要一个函数来根据Credit和StartNumber创建一个整数范围。这可以像上面一样简单,也可以是任何其他算法,具体取决于您对信用较高的广告的机会进行评级的程度。
您可以使用信用范围转换功能将一系列未显示的加号转换为整数序列。
作为扩展功能:
Id Credit => Range
00 01 00
01 01 01
02 02 02, 03 // credit 2: 2 numbers
03 03 04, 05, 06 // credit 3: 3 numbers
04 10 07, 08, 09, 10, 11, 12, 13, 14, 15, 16 // 10 numbers
用法:
static IEnumerable<int> ToRange(this int credit, int startNumber)
{
// example: Credit 40 is 40 times more chance than credit 1.
// so range length is equal to credit
return Enumerable.Range(startNumber, credit);
}
static IEnumerable<int> ToRange(this IEnumerable<Ad> adds)
{
int startNumber = 0;
foreach (Ad add in adds)
{
// only use ads that are not displayed yet to select a new Ad.
if (!ad.IsDisplayed)
{
var range = add.Credit.ToRange();
foreach (var value in range) yield return value;
}
}
}
问题在于,一旦您选择了第一个广告,第二个广告的机会就会改变。您需要创建一个新范围:
List<Ad> ads = ...
var range = ads.ToRange().ToList();
int selectedIndex = rnd.Next(range.Count);
var firstSelectedAdd = ads[selectedIndex];